diff options
Diffstat (limited to 'nx-X11/programs/Xserver/hw')
137 files changed, 79802 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/.gitignore b/nx-X11/programs/Xserver/hw/nxagent/.gitignore new file mode 100644 index 000000000..256534b63 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/.gitignore @@ -0,0 +1,3 @@ +miinitext.c +stubs.c +xpstubs.c diff --git a/nx-X11/programs/Xserver/hw/nxagent/Agent.h b/nx-X11/programs/Xserver/hw/nxagent/Agent.h new file mode 100644 index 000000000..af8b62810 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Agent.h @@ -0,0 +1,136 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright (c) 1995 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ + +#ifndef __Agent_H__ +#define __Agent_H__ + +/* + * Machines with a 64 bit library interface and a 32 bit + * server require name changes to protect the guilty. + */ + +#ifdef _XSERVER64 +#define _XSERVER64_tmp +#undef _XSERVER64 +typedef unsigned long XID64; +typedef unsigned long Mask64; +typedef unsigned long Atom64; +typedef unsigned long VisualID64; +typedef unsigned long Time64; +#define XID XID64 +#define Mask Mask64 +#define Atom Atom64 +#define VisualID VisualID64 +#define Time Time64 +typedef XID Window64; +typedef XID Drawable64; +typedef XID Font64; +typedef XID Pixmap64; +typedef XID Cursor64; +typedef XID Colormap64; +typedef XID GContext64; +typedef XID KeySym64; +#define Window Window64 +#define Drawable Drawable64 +#define Font Font64 +#define Pixmap Pixmap64 +#define Cursor Cursor64 +#define Colormap Colormap64 +#define GContext GContext64 +#define KeySym KeySym64 + +#define XlibAtom Atom64 +#define XlibWindow Window64 +#define XlibPixmap Pixmap64 +#define XlibFont Font64 +#define XlibKeySym KeySym64 +#define XlibXID XID64 + +#else /*_XSERVER64*/ + +#define XlibAtom Atom +#define XlibWindow Window +#define XlibPixmap Pixmap +#define XlibFont Font +#define XlibKeySym KeySym +#define XlibXID XID + +#endif /*_XSERVER64*/ + +#define NX_TRANS_SOCKET +#define GC XlibGC +#include <nx-X11/Xlib.h> +#include <X11/extensions/shape.h> +#undef GC + +#ifdef _XSERVER64_tmp +#define _XSERVER64 +#undef _XSERVER64_tmp +#undef XID +#undef Mask +#undef Atom +#undef VisualID +#undef Time +#undef Window +#undef Drawable +#undef Font +#undef Pixmap +#undef Cursor +#undef Colormap +#undef GContext +#undef KeySym +#endif /*_XSERVER64_tmp*/ + +#endif /* __Agent_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Args.c b/nx-X11/programs/Xserver/hw/nxagent/Args.c new file mode 100644 index 000000000..5db7e0110 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Args.c @@ -0,0 +1,2613 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#ifdef __sun +#include <strings.h> +#endif + +#include "X.h" +#include "Xproto.h" +#include "screenint.h" +#include "input.h" +#include "misc.h" +#include "globals.h" +#include "scrnintstr.h" +#include "dixstruct.h" +#include "servermd.h" +#include "opaque.h" + +#include "Agent.h" +#include "Display.h" +#include "Args.h" +#include "Options.h" +#include "Binder.h" +#include "Trap.h" +#include "Screen.h" +#include "Image.h" +#ifdef RENDER +#include "Render.h" +#endif +#include "Handlers.h" +#include "Error.h" +#include "Reconnect.h" +#include "Utils.h" + +/* + * NX includes and definitions. + */ + +#include "compext/Compext.h" +#include <nx/NXpack.h> + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef WATCH + +#ifdef WATCH + +#include "unistd.h" + +#endif + +#ifdef PANORAMIX + #define PANORAMIX_DISABLED_COND (noPanoramiXExtension || PanoramiXExtensionDisabledHack) +#else + #define PANORAMIX_DISABLED_COND TRUE +#endif + +#ifdef RANDR + #define RRXINERAMA_DISABLED_COND noRRXineramaExtension +#else + #define RRXINERAMA_DISABLED_COND TRUE +#endif + +/* + * Define this to force the dispatcher + * to always use the dumb scheduler. + */ + +#undef DISABLE_SMART_SCHEDULE + +int nxagentUserDefinedFontPath = 0; + +/* + * From X11/ImUtil.c. + */ + +extern int _XGetBitsPerPixel(Display *dpy, int depth); + +extern char dispatchExceptionAtReset; + +extern const char *__progname; + +char nxagentDisplayName[1024]; +Bool nxagentSynchronize = False; + +char nxagentShadowDisplayName[1024] = {0}; + +char nxagentWindowName[256]; +char nxagentDialogName[256]; +char nxagentSessionId[256] = {0}; +char *nxagentOptionFile; + +Bool nxagentFullGeneration = False; +int nxagentDefaultClass = TrueColor; +Bool nxagentUserDefaultClass = False; +int nxagentDefaultDepth; +Bool nxagentUserDefaultDepth = False; +struct UserGeometry nxagentUserGeometry = {0, 0, 0, 0, 0}; +Bool nxagentUserBorderWidth = False; +int nxagentNumScreens = 0; +Bool nxagentDoDirectColormaps = False; +Window nxagentParentWindow = 0; +Bool nxagentIpaq = False; + +int nxagentLockDeferLevel = 0; + +Bool nxagentResizeDesktopAtStartup = False; + +Bool nxagentUseNXTrans = False; +Bool nxagentForceNXTrans = False; + +int nxagentMaxAllowedResets = 0; + +char *nxagentKeyboard = NULL; + +Bool nxagentOnce = True; + +int nxagentRemoteMajor = -1; + +static void nxagentParseOptionString(char*); + +/* + * Get the caption to be used for helper dialogs + * from agent's window name passed as parameter. + */ + +static int nxagentGetDialogName(void); + +char nxagentVerbose = 0; + +char *nxagentKeystrokeFile = NULL; + +int ddxProcessArgument(int argc, char *argv[], int i) +{ + /* + * Ensure that the options are set to their defaults. + */ + + static Bool resetOptions = True; + + if (resetOptions == True) + { + char *envOptions = NULL; + char *envDisplay = NULL; + int j; + + nxagentInitOptions(); + + resetOptions = False; + + /* + * Ensure the correct order of options evaluation: + * the environment first, then those included in + * the options file and, last, the command line + * options. + */ + + envDisplay = getenv("DISPLAY"); + + if (envDisplay != NULL && strlen(envDisplay) == 0) + { + envDisplay = NULL; + } + + for (j = 0; j < argc; j++) + { + if ((!strcmp(argv[j], "-display")) && (j + 1 < argc)) + { + envOptions = malloc(strlen(argv[j + 1]) + 1); + + if (envOptions != NULL) + { + envOptions = strcpy(envOptions, argv[j + 1]); + } + #ifdef WARNING + else + { + fprintf(stderr, "ddxProcessArgument: WARNING! failed string allocation.\n"); + } + #endif + + break; + } + } + + if ((envOptions == NULL) && (envDisplay != NULL)) + { + envOptions = malloc(strlen(envDisplay) + 1); + + if (envOptions != NULL) + { + envOptions = strcpy(envOptions, envDisplay); + } + #ifdef WARNING + else + { + fprintf(stderr, "ddxProcessArgument: WARNING! failed string allocation.\n"); + } + #endif + } + + if (envOptions != NULL) + { + nxagentParseOptionString(envOptions); + + free(envOptions); + } + + for (j = 0; j < argc; j++) + { + if ((!strcmp(argv[j], "-options") || !strcmp(argv[j], "-option")) && j + 1 < argc) + { + if (nxagentOptionFile) + { + nxagentOptionFile = (char *) realloc(nxagentOptionFile, strlen(argv[j + 1]) + 1); + } + else + { + nxagentOptionFile = (char *) malloc(strlen(argv[j + 1]) +1); + } + + if (nxagentOptionFile != NULL) + { + nxagentOptionFile = strcpy(nxagentOptionFile, argv[j + 1]); + } + #ifdef WARNING + else + { + fprintf(stderr, "ddxProcessArgument: WARNING! failed string allocation.\n"); + } + #endif + + break; + } + } + + if (nxagentOptionFile) + { + nxagentProcessOptionsFile(); + } + } + + if (!strcmp(argv[i], "-B")) + { + #ifdef TEST + fprintf(stderr, "ddxProcessArgument: Checking the NX binder option.\n"); + #endif + + if (nxagentCheckBinder(argc, argv, i) > 0) + { + /* + * We are going to run the agent with the + * 'binder' option. Go straight to the + * proxy loop. + */ + + #ifdef TEST + fprintf(stderr, "ddxProcessArgument: Entering the NX proxy binder loop.\n"); + #endif + + nxagentBinderLoop(); + + /* + * This will make an exit. + */ + + nxagentBinderExit(0); + } + else + { + /* + * Exit with an error. + */ + + nxagentBinderExit(1); + } + } + + if (!strcmp(argv[i], "-display")) + { + if (++i < argc) + { + strncpy(nxagentDisplayName, argv[i], 1023); + + nxagentDisplayName[1023] = '\0'; + + return 2; + } + + return 0; + } + + if (!strcmp(argv[i], "-id")) + { + if (++i < argc) + { + strncpy(nxagentSessionId, argv[i], 255); + + *(nxagentSessionId + 255) = '\0'; + + return 2; + } + + return 0; + } + + /* + * This had to be '-options' since the beginning + * but was '-option' by mistake. Now we have to + * handle the backward compatibility. + */ + + if (!strcmp(argv[i], "-options") || !strcmp(argv[i], "-option")) + { + if (++i < argc) + { + int size; + + if (nxagentOptionFile != NULL) + { + free(nxagentOptionFile); + + nxagentOptionFile = NULL; + } + + if ((size = strlen(argv[i])) < 1024) + { + if ((nxagentOptionFile = malloc(size + 1)) == NULL) + { + FatalError("malloc failed"); + } + + strncpy(nxagentOptionFile, argv[i], size); + + nxagentOptionFile[size] = '\0'; + } + else + { + /* + * It is useless to store the file name + * that has just been truncated. + */ + + #ifdef WARNING + fprintf(stderr, "ddxProcessArgument: WARNING! Option file name " + "too long. It will be ignored.\n"); + #endif + } + + return 2; + } + + return 0; + } + + if (!strcmp(argv[i], "-sync")) { + nxagentSynchronize = True; + return 1; + } + + if (!strcmp(argv[i], "-full")) { + nxagentFullGeneration = True; + return 1; + } + + if (!strcmp(argv[i], "-class")) { + if (++i < argc) { + if (!strcmp(argv[i], "StaticGray")) { + nxagentDefaultClass = StaticGray; + nxagentUserDefaultClass = True; + return 2; + } + else if (!strcmp(argv[i], "GrayScale")) { + nxagentDefaultClass = GrayScale; + nxagentUserDefaultClass = True; + return 2; + } + else if (!strcmp(argv[i], "StaticColor")) { + nxagentDefaultClass = StaticColor; + nxagentUserDefaultClass = True; + return 2; + } + else if (!strcmp(argv[i], "PseudoColor")) { + nxagentDefaultClass = PseudoColor; + nxagentUserDefaultClass = True; + return 2; + } + else if (!strcmp(argv[i], "TrueColor")) { + nxagentDefaultClass = TrueColor; + nxagentUserDefaultClass = True; + return 2; + } + else if (!strcmp(argv[i], "DirectColor")) { + nxagentDefaultClass = DirectColor; + nxagentUserDefaultClass = True; + return 2; + } + } + return 0; + } + + if (!strcmp(argv[i], "-cc")) { + if (++i < argc && sscanf(argv[i], "%i", &nxagentDefaultClass) == 1) { + if (nxagentDefaultClass >= 0 && nxagentDefaultClass <= 5) { + nxagentUserDefaultClass = True; + /* lex the OS layer process it as well, so return 0 */ + } + } + return 0; + } + + if (!strcmp(argv[i], "-depth")) { + if (++i < argc && sscanf(argv[i], "%i", &nxagentDefaultDepth) == 1) { + if (nxagentDefaultDepth > 0) { + nxagentUserDefaultDepth = True; + return 2; + } + } + return 0; + } + + /* + * These options are now useless and are + * parsed only for compatibility with + * older versions. + */ + + if (!strcmp(argv[i], "-fast") || + !strcmp(argv[i], "-slow") || + !strcmp(argv[i], "-hint") || + !strcmp(argv[i], "-sss")) + { + fprintf(stderr, "Warning: Ignoring deprecated command line option '%s'.\n", + argv[i]); + + return 1; + } + + if (!strcmp(argv[i], "-backingstore")) + { + if (++i < argc) + { + if (!strcmp(argv[i], "0")) + { + nxagentChangeOption(BackingStore, BackingStoreNever); + } + else + { + nxagentChangeOption(BackingStore, BackingStoreForce); + } + + return 2; + } + + return 0; + } + + if (!strcmp(argv[i], "-streaming")) + { + if (++i < argc) + { + if (!strcmp(argv[i], "0")) + { + nxagentChangeOption(Streaming, 0); + } + else + { + nxagentChangeOption(Streaming, 1); + } + + return 2; + } + + return 0; + } + + if (!strcmp(argv[i], "-defer")) + { + int level; + + if (++i < argc && + sscanf(argv[i], "%i", &level) == 1 && + level >= 0 && level <= 2) + { + if (nxagentOption(Shadow) == 0) + { + nxagentChangeOption(DeferLevel, level); + + /* + * The defer level set with the command + * line is not changed when the session + * is resumed. + */ + + nxagentLockDeferLevel = 1; + } + + return 2; + } + + return 0; + } + + if (!strcmp(argv[i], "-irlimit")) + { + int limit; + + if (++i < argc && + sscanf(argv[i], "%i", &limit) == 1) + { + nxagentChangeOption(ImageRateLimit, limit); + + + return 2; + } + + return 0; + } + + if (!strcmp(argv[i], "-tile")) + { + int width; + int height; + + if (++i < argc && + sscanf(argv[i], "%ix%i", &width, &height) == 2 && + width >= 32 && height >= 32) + { + nxagentChangeOption(TileWidth, width); + nxagentChangeOption(TileHeight, height); + + return 2; + } + + return 0; + } + + if (strcmp(argv[i], "-fp") == 0) + { + if(++i < argc) + { + + #ifdef TEST + fprintf(stderr, "ddxProcessArgument: User defined font path [%s].\n", argv[i]); + #endif + + nxagentUserDefinedFontPath = 1; + + defaultFontPath = argv[i]; + } + else + { + UseMsg(); + } + } + + if (!strcmp(argv[i], "-geometry")) + { + if (++i < argc) + { + if (!strcmp(argv[i],"fullscreen")) + { + nxagentChangeOption(Fullscreen, True); + + nxagentChangeOption(AllScreens, True); + } + else if (!strcmp(argv[i],"ipaq")) + { + nxagentChangeOption(Fullscreen, True); + + nxagentChangeOption(AllScreens, True); + + nxagentIpaq = True; + } + else + { + if (nxagentUserGeometry.flag == 0) + { + nxagentUserGeometry.flag = XParseGeometry(argv[i], + &nxagentUserGeometry.X, + &nxagentUserGeometry.Y, + &nxagentUserGeometry.Width, + &nxagentUserGeometry.Height); + } + } + + if (nxagentUserGeometry.flag || (nxagentOption(Fullscreen) == 1)) return 2; + } + + return 0; + } + + if (!strcmp(argv[i], "-bw")) + { + int BorderWidth; + + if (++i < argc && sscanf(argv[i], "%i", &BorderWidth) == 1) + { + nxagentChangeOption(BorderWidth, BorderWidth); + + if (nxagentOption(BorderWidth) >= 0) + { + nxagentUserBorderWidth = True; + + return 2; + } + } + + return 0; + } + + if (!strcmp(argv[i], "-name")) + { + if (++i < argc) + { + strncpy(nxagentWindowName, argv[i], 255); + + *(nxagentWindowName + 255) = '\0'; + + return 2; + } + + return 0; + } + + if (!strcmp(argv[i], "-scrns")) { + if (++i < argc && sscanf(argv[i], "%i", &nxagentNumScreens) == 1) { + if (nxagentNumScreens > 0) { + if (nxagentNumScreens > MAXSCREENS) { + ErrorF("Maximum number of screens is %d.\n", MAXSCREENS); + nxagentNumScreens = MAXSCREENS; + } + return 2; + } + } + return 0; + } + + if (!strcmp(argv[i], "-install")) { + nxagentDoDirectColormaps = True; + return 1; + } + + if (!strcmp(argv[i], "-parent")) { + if (++i < argc) { + nxagentParentWindow = (XID) strtol (argv[i], (char**)NULL, 0); + return 2; + } + } + + if (!strcmp(argv[i], "-forcenx")) { + nxagentForceNXTrans = True; + return 1; + } + + if (!strcmp(argv[i], "-norootlessexit")) { + nxagentChangeOption(NoRootlessExit, True); + return 1; + } + + + if (!strcmp(argv[i], "-noonce")) + { + nxagentOnce = False; + return 1; + } + + if (!strcmp(argv[i], "-kbtype") || + !strcmp(argv[i], "-keyboard")) + { + if (++i < argc) + { + int size; + + if (nxagentKeyboard != NULL) + { + free(nxagentKeyboard); + + nxagentKeyboard = NULL; + } + + if ((size = strlen(argv[i])) < 256) + { + if ((nxagentKeyboard = malloc(size + 1)) == NULL) + { + FatalError("malloc failed"); + } + + strncpy(nxagentKeyboard, argv[i], size); + + nxagentKeyboard[size] = '\0'; + } + #ifdef WARNING + else + { + /* + * it is useless to remember a kbtype + * option that has just been truncated. + */ + + fprintf(stderr, "ddxProcessArgument: WARNING! Option [%s] too long. " + "It will be ignored.\n", argv[i]); + } + #endif + + return 2; + } + + return 0; + } + + if (!strcmp(argv[i], "-extensions")) + { + return 1; + } + + #ifdef RENDER + if (!strcmp(argv[i], "-norender")) + { + nxagentRenderEnable = False; + + return 1; + } + #endif + + if (!strcmp(argv[i], "-nocomposite")) + { + nxagentChangeOption(Composite, 0); + + return 1; + } + + if (!strcmp(argv[i], "-nodamage")) + { + nxagentChangeOption(UseDamage, 0); + + return 1; + } + + /* + * The original -noreset option, disabling + * dispatchExceptionAtReset, is the default. + * Use this option to restore the original + * behaviour. + */ + + if (!strcmp(argv[i], "-reset")) + { + nxagentChangeOption(Reset, True); + + return 1; + } + + if (!strcmp(argv[i], "-persistent")) + { + nxagentChangeOption(Persistent, True); + + return 1; + } + + if (!strcmp(argv[i], "-nopersistent")) + { + nxagentChangeOption(Persistent, False); + + return 1; + } + + if (!strcmp(argv[i], "-noshmem")) + { + nxagentChangeOption(SharedMemory, False); + + return 1; + } + + if (!strcmp(argv[i], "-shmem")) + { + nxagentChangeOption(SharedMemory, True); + + return 1; + } + + if (!strcmp(argv[i], "-noignore")) + { + nxagentChangeOption(DeviceControl, True); + + nxagentChangeOption(DeviceControlUserDefined , True); + + return 1; + } + + if (!strcmp(argv[i], "-nokbreset")) + { + nxagentChangeOption(ResetKeyboardAtResume, False); + + return 1; + } + + if (!strcmp(argv[i], "-noxkblock")) + { + nxagentChangeOption(InhibitXkb, 0); + + return 1; + } + + /* + * Enable pseudo-rootless mode. + */ + + if (!strcmp(argv[i], "-R")) + { + if (nxagentOption(Binder) == UNDEFINED || + nxagentOption(Desktop) == UNDEFINED || + nxagentOption(Rootless) == UNDEFINED) + { + nxagentChangeOption(Binder, False); + nxagentChangeOption(Desktop, False); + nxagentChangeOption(Rootless, True); + } + return 1; + } + + /* + * Enable the "desktop" mode. This is + * the default. + */ + + if (!strcmp(argv[i], "-D")) + { + nxagentChangeOption(Binder, False); + nxagentChangeOption(Rootless, False); + nxagentChangeOption(Desktop, True); + + return 1; + } + + /* + * Enable the "shadow" mode. + */ + + if (!strcmp(argv[i], "-S")) + { + nxagentChangeOption(Shadow, 1); + nxagentChangeOption(DeferLevel, 0); + nxagentChangeOption(Persistent, 0); + + return 1; + } + + if (!strcmp(argv[i], "-shadow")) + { + if (++i < argc) + { + strncpy(nxagentShadowDisplayName, argv[i], 1023); + + if (strcmp(nxagentShadowDisplayName, "") == 0) + { + FatalError("Invalid shadow display option"); + } + + *(nxagentShadowDisplayName + 1023) = '\0'; + + return 2; + } + + return 0; + } + + + if (!strcmp(argv[i], "-shadowmode")) + { + if (++i < argc) + { + if (!strcmp(argv[i], "0")) + { + nxagentChangeOption(ViewOnly, 1); + } + else + { + nxagentChangeOption(ViewOnly, 0); + } + + return 2; + } + + return 0; + } + + /* + * Enable the auto-disconnect timeout. + */ + + if (!strcmp(argv[i], "-timeout")) + { + int seconds; + + if (++i < argc && sscanf(argv[i], "%i", &seconds) == 1) + { + if (seconds >= 0) + { + if (seconds > 0 && seconds < 60) + { + seconds = 60; + } + + nxagentChangeOption(Timeout, seconds); + + return 2; + } + } + + return 0; + } + + /* + * The return value for -query, -broadcast and + * -indirect must be 0 to let the dix layer pro- + * cess these options. + */ + + if (!strcmp(argv[i], "-query")) + + { + nxagentChangeOption(Desktop, True); + nxagentChangeOption(Xdmcp, True); + + nxagentMaxAllowedResets = 0; + + return 0; + } + + if (!strcmp(argv[i], "-broadcast")) + + { + nxagentChangeOption(Desktop, True); + nxagentChangeOption(Xdmcp, True); + + nxagentMaxAllowedResets = 0; + + return 0; + } + + if (!strcmp(argv[i], "-indirect")) + { + nxagentChangeOption(Desktop, True); + nxagentChangeOption(Xdmcp, True); + + nxagentMaxAllowedResets = 1; + + return 0; + } + + if (!strcmp(argv[i], "-noshpix")) + { + nxagentChangeOption(SharedPixmaps, False); + + return 1; + } + + if (!strcmp(argv[i], "-shpix")) + { + nxagentChangeOption(SharedPixmaps, True); + + return 1; + } + + if (!strcmp(argv[i], "-clipboard")) + { + if ((!strcmp(argv[i+1], "both")) || (!strcmp(argv[i+1], "1"))) + { + nxagentChangeOption(Clipboard, ClipboardBoth); + } + else if (!strcmp(argv[i+1], "client")) + { + nxagentChangeOption(Clipboard, ClipboardClient); + } + else if (!strcmp(argv[i+1], "server")) + { + nxagentChangeOption(Clipboard, ClipboardServer); + } + else if ((!strcmp(argv[i+1], "none")) || (!strcmp(argv[i+1], "1"))) + { + nxagentChangeOption(Clipboard, ClipboardNone); + } + else + { + nxagentChangeOption(Clipboard, ClipboardBoth); + } + + return 2; + } + + if (!strcmp(argv[i], "-bs")) + { + nxagentChangeOption(BackingStore, BackingStoreNever); + return 1; + } + + if (!strcmp(argv[i], "-verbose")) + { + nxagentVerbose = 1; + + return 1; + } + + if (!strcmp(argv[i], "-keystrokefile")) + { + if (i + 1 < argc) + { + if (NULL != (nxagentKeystrokeFile = strdup(argv[i + 1]))) + { + return 2; + } else { + FatalError("malloc failed"); + } + } + return 0; + } + + /* + * Disable Xinerama (i.e. fake it in Screen.c) if somehow Xinerama support + * has been disabled on the cmdline. + */ + if (PANORAMIX_DISABLED_COND && RRXINERAMA_DISABLED_COND) + nxagentChangeOption(Xinerama, 0); + + return 0; +} + +static void nxagentParseOptions(char *name, char *value) +{ + int size, argc; + + char *argv[2] = { NULL, NULL }; + + #ifdef TEST + fprintf(stderr, "nxagentParseOptions: Processing option '%s' = '%s'.\n", + validateString(name), validateString(value)); + #endif + + if (!strcmp(name, "kbtype") || + !strcmp(name, "keyboard") || + !strcmp(name, "id") || + !strcmp(name, "display") || + !strcmp(name, "clipboard") || + !strcmp(name, "geometry") || + !strcmp(name, "option") || + !strcmp(name, "options") || + !strcmp(name, "shadow") || + !strcmp(name, "shadowmode") || + !strcmp(name, "streaming") || + !strcmp(name, "defer") || + !strcmp(name, "tile")) + { + argv[1] = value; + + argc = 2; + } + else if (!strcmp(name, "R") && !strcmp(value, "1")) + { + argc = 1; + } + else if (!strcmp(name, "fast") || !strcmp(name, "slow")) + { + fprintf(stderr, "Warning: Ignoring deprecated option '%s'.\n", name); + + return; + } + else if (!strcmp(name, "render")) + { + if (nxagentReconnectTrap == True) + { + #ifdef DEBUG + fprintf(stderr, "nxagentParseOptions: Ignoring option 'render' at reconnection.\n"); + #endif + } + else if (nxagentRenderEnable == UNDEFINED) + { + if (!strcmp(value, "1")) + { + nxagentRenderEnable = True; + } + else if (!strcmp(value, "0")) + { + nxagentRenderEnable = False; + } + else + { + fprintf(stderr, "Warning: Ignoring bad value '%s' for option 'render'.\n", + validateString(value)); + } + } + + return; + } + else if (!strcmp(name, "state")) + { + setStatePath(value); + return; + } + else if (!strcmp(name, "fullscreen")) + { + if (nxagentReconnectTrap == True) + { + #ifdef DEBUG + fprintf(stderr, "nxagentParseOptions: Ignoring option 'fullscreen' at reconnection.\n"); + #endif + } + else if (!strcmp(value, "1")) + { + nxagentChangeOption(Fullscreen, True); + + nxagentChangeOption(AllScreens, True); + } + else if (!strcmp(value, "0")) + { + nxagentChangeOption(Fullscreen, False); + + nxagentChangeOption(AllScreens, False); + } + else + { + fprintf(stderr, "Warning: Ignoring bad value '%s' for option 'fullscreen'.\n", + validateString(value)); + } + + return; + } + else if (!strcmp(name, "shpix")) + { + if (!strcmp(value, "1")) + { + nxagentChangeOption(SharedPixmaps, True); + } + else if (!strcmp(value, "0")) + { + nxagentChangeOption(SharedPixmaps, False); + } + else + { + fprintf(stderr, "Warning: Ignoring bad value '%s' for option 'shpix'.\n", + validateString(value)); + } + + return; + } + else if (!strcmp(name, "shmem")) + { + if (!strcmp(value, "1")) + { + nxagentChangeOption(SharedMemory, True); + } + else if (!strcmp(value, "0")) + { + nxagentChangeOption(SharedMemory, False); + } + else + { + fprintf(stderr, "Warning: Ignoring bad value '%s' for option 'shmem'.\n", + validateString(value)); + } + + return; + } + else if (!strcmp(name, "composite")) + { + if (!strcmp(value, "1")) + { + nxagentChangeOption(Composite, 1); + } + else if (!strcmp(value, "0")) + { + nxagentChangeOption(Composite, 0); + } + else + { + fprintf(stderr, "Warning: Ignoring bad value '%s' for option 'composite'.\n", + validateString(value)); + } + + return; + } + else if (!strcmp(name, "xinerama")) + { +#if !defined(PANORAMIX) && !defined(RANDR) + nxagentChangeOption(Xinerama, 0); + fprintf(stderr, "Warning: No Xinerama support compiled into %s.\n", __progname); + return; +#else + if (PANORAMIX_DISABLED_COND && RRXINERAMA_DISABLED_COND) + { + nxagentChangeOption(Xinerama, 0); + fprintf(stderr, "Warning: XINERAMA extension has been disabled on %s startup.\n", __progname); + return; + } + + if (!strcmp(value, "1")) + { + nxagentChangeOption(Xinerama, 1); + return; + } + else if (!strcmp(value, "0")) + { + nxagentChangeOption(Xinerama, 0); + } + else + { + fprintf(stderr, "Warning: Ignoring bad value '%s' for option 'xinerama'.\n", + validateString(value)); + } + return; +#endif + } + else if (!strcmp(name, "resize")) + { + if (nxagentOption(DesktopResize) == 0 || strcmp(value, "0") == 0) + { + nxagentResizeDesktopAtStartup = 0; + } + else if (strcmp(value, "1") == 0) + { + nxagentResizeDesktopAtStartup = 1; + } + else + { + fprintf(stderr, "Warning: Ignoring bad value '%s' for option 'resize'.\n", + validateString(value)); + } + + return; + } + else if (!strcmp(name, "backingstore")) + { + if (!strcmp(value, "0")) + { + nxagentChangeOption(BackingStore, BackingStoreNever); + } + else + { + nxagentChangeOption(BackingStore, BackingStoreForce); + } + + return; + } + else if (!strcmp(name, "menu")) + { + if (!strcmp(value, "0")) + { + nxagentChangeOption(Menu, 0); + } + else + { + nxagentChangeOption(Menu, 1); + } + + return; + } + else if (strcmp(name, "shadowuid") == 0) + { + nxagentShadowUid = atoi(value); + + return; + } + else if (strcmp(name, "clients") == 0) + { + strcpy(nxagentClientsLogName, value); + + return; + } + else if (strcmp(name, "client") == 0) + { + if (strcmp(value, "winnt") == 0 || strcmp(value, "windows") == 0) + { + nxagentChangeOption(ClientOs, ClientOsWinnt); + } + else if (strcmp(value, "linux") == 0) + { + nxagentChangeOption(ClientOs, ClientOsLinux); + } + else if (strcmp(value, "solaris") == 0) + { + nxagentChangeOption(ClientOs, ClientOsSolaris); + } + else if (strcmp(value, "macosx") == 0) + { + nxagentChangeOption(ClientOs, ClientOsMac); + } + + return; + } + else if (strcmp(name, "copysize") == 0) + { + nxagentChangeOption(CopyBufferSize, atoi(value)); + + return; + } + else if (strcmp(name, "clipboard") == 0) + { + if ((strcmp(value, "both") == 0) || (strcmp(value, "1") == 0)) + { + nxagentChangeOption(Clipboard, ClipboardBoth); + } + else if (strcmp(value, "client") == 0) + { + nxagentChangeOption(Clipboard, ClipboardClient); + } + else if (strcmp(value, "server") == 0) + { + nxagentChangeOption(Clipboard, ClipboardServer); + } + else if ((strcmp(value, "none") == 0) || (strcmp(value, "0") == 0)) + { + nxagentChangeOption(Clipboard, ClipboardNone); + } + else + { + nxagentChangeOption(Clipboard, ClipboardBoth); + } + } + else if (!strcmp(name, "sleep")) + { + long sleep_parse = 0; + + errno = 0; + sleep_parse = strtol(value, NULL, 10); + + if ((errno) && (0 == sleep_parse)) + { + fprintf(stderr, "nxagentParseOptions: Unable to convert value [%s] of option [%s]. " + "Ignoring option.\n", + validateString(value), validateString(name)); + + return; + } + + if ((long) UINT_MAX < sleep_parse) + { + sleep_parse = UINT_MAX; + + fprintf(stderr, "nxagentParseOptions: Warning: value [%s] of option [%s] " + "out of range, clamped to [%lu].\n", + validateString(value), validateString(name), sleep_parse); + } + + if (0 > sleep_parse) + { + sleep_parse = 0; + + fprintf(stderr, "nxagentParseOptions: Warning: value [%s] of option [%s] " + "out of range, clamped to [%lu].\n", + validateString(value), validateString(name), sleep_parse); + } + + nxagentChangeOption(SleepTime, sleep_parse); + + return; + } + else if (!strcmp(name, "tolerancechecks")) + { + if (strcmp(value, "strict") == 0) + { + nxagentChangeOption(ReconnectTolerance, ToleranceChecksStrict); + } + else if (strcmp(value, "safe") == 0) + { + nxagentChangeOption(ReconnectTolerance, ToleranceChecksSafe); + } + else if (strcmp(value, "risky") == 0) + { + nxagentChangeOption(ReconnectTolerance, ToleranceChecksRisky); + } + else if (strcmp(value, "bypass") == 0) + { + nxagentChangeOption(ReconnectTolerance, ToleranceChecksBypass); + } + else + { + /* + * Check for a matching integer. Or any integer, really. + */ + long tolerance_parse = 0; + + errno = 0; + tolerance_parse = strtol(value, NULL, 10); + + if ((errno) && (0 == tolerance_parse)) + { + fprintf(stderr, "nxagentParseOptions: Unable to convert value [%s] of option [%s]. " + "Ignoring option.\n", + validateString(value), validateString(name)); + + return; + } + + if ((long) UINT_MAX < tolerance_parse) + { + tolerance_parse = UINT_MAX; + + fprintf(stderr, "nxagentParseOptions: Warning: value [%s] of option [%s] " + "out of range, clamped to [%lu].\n", + validateString(value), validateString(name), tolerance_parse); + } + + if (0 > tolerance_parse) + { + tolerance_parse = 0; + + fprintf(stderr, "nxagentParseOptions: Warning: value [%s] of option [%s] " + "out of range, clamped to [%lu].\n", + validateString(value), validateString(name), tolerance_parse); + } + + #ifdef TEST + switch (tolerance_parse) { + case ToleranceChecksStrict: + case ToleranceChecksSafe: + case ToleranceChecksRisky: + case ToleranceChecksBypass: + break; + default: + fprintf(stderr, "nxagentParseOptions: Warning: value [%s] of " + "option [%s] unknown, will be mapped to " + "\"Bypass\" [%u] value internally.\n", + validateString(value), validateString(name), + (unsigned int)ToleranceChecksBypass); + } + #endif + + nxagentChangeOption(ReconnectTolerance, tolerance_parse); + } + + return; + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentParseOptions: Ignored option [%s] with value [%s].\n", + validateString(name), validateString(value)); + #endif + + return; + } + + /* + * Before passing the not yet evaluated options + * to ddxProcessArgument(), we have to add a dash + * as prefix. + */ + + if ((size = strlen(name) + 1) > 1) + { + if ((argv[0] = malloc(size + 1)) == NULL) + { + fprintf(stderr, "Warning: Ignoring option '%s' due to lack of memory.\n", + name); + + return; + } + + *argv[0] = '-'; + + memcpy(argv[0] + 1, name, size); + } + + ddxProcessArgument(argc, argv, 0); + + free(argv[0]); +} + +static void nxagentParseOptionString(char *string) +{ + char *value = NULL; + char *option = NULL; + char *delimiter = NULL; + + /* + * Remove the port specification. + */ + + delimiter = rindex(string, ':'); + + if (delimiter) + { + *delimiter = 0; + } + else + { + fprintf(stderr, "Warning: Option file doesn't contain a port specification.\n"); + } + + while ((option = strtok(option ? NULL : string, ","))) + { + delimiter = rindex(option, '='); + + if (delimiter) + { + *delimiter = 0; + value = delimiter + 1; + } + else + { + value = NULL; + } + + nxagentParseOptions(option, value); + } +} + +void nxagentProcessOptionsFile() +{ + FILE *file; + char *data; + + int offset; + int size; + + int sizeOfFile; + int maxFileSize = 1024; + + #ifdef DEBUG + fprintf(stderr, "nxagentProcessOptionsFile: Going to process option the file [%s].\n", + validateString(nxagentOptionFile)); + #endif + + /* + * Init statePath + */ + setStatePath(""); + + if (nxagentOptionFile == NULL) + { + return; + } + + if ((file = fopen(nxagentOptionFile, "r")) == NULL) + { + fprintf(stderr, "Warning: Couldn't open option file '%s'. Error is '%s'.\n", + validateString(nxagentOptionFile), strerror(errno)); + + goto nxagentProcessOptionsFileExit; + } + + if (fseek(file, 0, SEEK_END) != 0) + { + fprintf(stderr, "Warning: Couldn't position inside option file '%s'. Error is '%s'.\n", + validateString(nxagentOptionFile), strerror(errno)); + + goto nxagentProcessOptionsFileClose; + } + + if ((sizeOfFile = ftell(file)) == -1) + { + fprintf(stderr, "Warning: Couldn't get the size of option file '%s'. Error is '%s'.\n", + validateString(nxagentOptionFile), strerror(errno)); + + goto nxagentProcessOptionsFileClose; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentProcessOptionsFile: Processing option file [%s].\n", + validateString(nxagentOptionFile)); + #endif + + rewind(file); + + if (sizeOfFile > maxFileSize) + { + fprintf(stderr, "Warning: Maximum file size exceeded for options '%s'.\n", + validateString(nxagentOptionFile)); + + goto nxagentProcessOptionsFileClose; + } + + if ((data = malloc(sizeOfFile + 1)) == NULL) + { + fprintf(stderr, "Warning: Memory allocation failed processing file '%s'.\n", + validateString(nxagentOptionFile)); + + goto nxagentProcessOptionsFileClose; + } + + offset = 0; + size = 0; + + for (;;) + { + size_t result = fread(data + offset, 1, sizeOfFile, file); + + if (ferror(file) != 0) + { + fprintf(stderr, "Warning: Error reading the option file '%s'.\n", + validateString(nxagentOptionFile)); + + goto nxagentProcessOptionsFileFree; + } + + size += result; + offset += result; + + if (feof(file) != 0 || (size == sizeOfFile)) + { + break; + } + } + + if (size != sizeOfFile) + { + fprintf(stderr, "Warning: Premature end of option file '%s' while reading.\n", + validateString(nxagentOptionFile)); + + goto nxagentProcessOptionsFileFree; + } + + /* + * Truncate the buffer to the first line. + */ + + for (offset = 0; (offset < sizeOfFile) && (data[offset] != '\n'); offset++); + + data[offset] = 0; + + nxagentParseOptionString(data); + +nxagentProcessOptionsFileFree: + + if (data != NULL) + { + free(data); + } + +nxagentProcessOptionsFileClose: + + if (fclose(file) != 0) + { + fprintf(stderr, "Warning: Couldn't close option file '%s'. Error is '%s'.\n", + validateString(nxagentOptionFile), strerror(errno)); + } + +nxagentProcessOptionsFileExit: + + return; +} + +/* + * FIXME: Transport initialization, shouldn't depend upon + * argv[], because we call it at every reconnection. + */ + +Bool nxagentPostProcessArgs(char* name, Display* dpy, Screen* scr) +{ + Bool useNXTrans = False; + + #ifdef WATCH + + fprintf(stderr, "nxagentPostProcessArgs: Watchpoint 2.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +N/A +*/ + + sleep(30); + + #endif + + if ((nxagentOption(Rootless) == 1) && nxagentOption(Fullscreen) == 1) + { + #ifdef TEST + fprintf(stderr, "WARNING: Ignoring fullscreen option for rootless session.\n"); + #endif + + nxagentChangeOption(Fullscreen, False); + } + + /* + * Ensure we have a valid name for children dialogs. + */ + + nxagentGetDialogName(); + + /* + * Ensure we have a valid name for window name. + */ + + if (*nxagentWindowName == '\0') + { + strncpy(nxagentWindowName, "NX", 255); + + *(nxagentWindowName + 255) = '\0'; + } + + /* + * Note that use of NX packed images as well as + * render extension could be later disabled due + * to the fact that session is running nested + * in a nxagent server. + */ + + if (nxagentForceNXTrans) + { + useNXTrans = True; + } + else if ((strncasecmp(name, "nx/", 3) == 0) || + (strncasecmp(name, "nx:", 3) == 0) || + (strncasecmp(name, "nx,", 3) == 0) || + (strcasecmp(name, "nx") == 0)) + { + useNXTrans = True; + } + + if (useNXTrans == True) + { + unsigned int linkType = LINK_TYPE_NONE; + + unsigned int localMajor = 0; + unsigned int localMinor = 0; + unsigned int localPatch = 0; + + unsigned int remoteMajor = 0; + unsigned int remoteMinor = 0; + unsigned int remotePatch = 0; + + int splitTimeout = 0; + int motionTimeout = 0; + + int splitMode = 0; + int splitSize = 0; + + unsigned int packMethod = PACK_NONE; + unsigned int packQuality = 9; + + int dataLevel = 0; + int streamLevel = 0; + int deltaLevel = 0; + + unsigned int loadCache = 0; + unsigned int saveCache = 0; + unsigned int startupCache = 0; + + unsigned int enableClient = 0; + unsigned int enableServer = 0; + + unsigned int clientSegment = 0; + unsigned int serverSegment = 0; + + unsigned int clientSize = 0; + unsigned int serverSize = 0; + + if (NXGetControlParameters(dpy, &linkType, &localMajor, &localMinor, + &localPatch, &remoteMajor, &remoteMinor, &remotePatch, + &splitTimeout, &motionTimeout, &splitMode, &splitSize, + &packMethod, &packQuality, &dataLevel, &streamLevel, + &deltaLevel, &loadCache, &saveCache, &startupCache) == 0) + { + fprintf(stderr, "Warning: Failed to get the control parameters.\n"); + } + + nxagentChangeOption(LinkType, linkType); + + #ifdef TEST + fprintf(stderr, "nxagentPostProcessArgs: Got local version [%d.%d.%d] remote version [%d.%d.%d].\n", + localMajor, localMinor, localPatch, remoteMajor, remoteMinor, remotePatch); + + fprintf(stderr, "nxagentPostProcessArgs: Got split timeout [%d] motion timeout [%d].\n", + splitTimeout, motionTimeout); + + fprintf(stderr, "nxagentPostProcessArgs: Got split mode [%d] split size [%d].\n", + splitMode, splitSize); + + fprintf(stderr, "nxagentPostProcessArgs: Got preferred pack method [%d] and quality [%d].\n", + packMethod, packQuality); + #endif + + if (remoteMajor < 2) + { + #ifdef TEST + fprintf(stderr, "nxagentPostProcessArgs: WARNING! Using backward compatible alpha encoding.\n"); + #endif + + nxagentAlphaCompat = 1; + } + else + { + nxagentAlphaCompat = 0; + } + + nxagentRemoteMajor = remoteMajor; + + if (nxagentPackMethod == -1) + { + nxagentPackMethod = packMethod; + } + + if (nxagentPackQuality == -1) + { + nxagentPackQuality = packQuality; + } + + /* + * Set the minimum size of images being + * streamed. + */ + + if (nxagentSplitThreshold == -1) + { + nxagentSplitThreshold = splitSize; + } + + /* + * Let the remote proxy use the shared memory + * extension, if supported by the X server. + * The client part is not useful and not impl- + * emented. The size of the segment is chosen + * by the user. The only purpose of the message + * is to reserve the XID that will be used by + * the remote. + */ + + enableClient = 0; + enableServer = 1; + + if (NXGetShmemParameters(dpy, &enableClient, &enableServer, &clientSegment, + &serverSegment, &clientSize, &serverSize) == 0) + { + fprintf(stderr, "Warning: Failed to get the shared memory parameters.\n"); + } + + if (enableServer == 1) + { + fprintf(stderr, "Info: Using shared memory parameters %d/%d/%d/%dK.\n", + nxagentOption(SharedMemory), nxagentOption(SharedPixmaps), + enableServer, serverSize / 1024); + } + else + { + fprintf(stderr, "Info: Using shared memory parameters %d/%d/0/0K.\n", + nxagentOption(SharedMemory), nxagentOption(SharedPixmaps)); + } + + /* + * We don't need the NoExpose events. Block + * them at the proxy side. + */ + + NXSetExposeParameters(nxagentDisplay, 1, 1, 0); + } + else + { + /* + * We don't have a proxy on the remote side. + */ + + nxagentChangeOption(LinkType, LINK_TYPE_NONE); + } + + /* + * Set the lossless and lossy pack methods + * based on the user's preferences and the + * selected link type. + */ + + nxagentSetPackMethod(); + + /* + * If not set, set the defer level and the + * synchronization timeout based on the link + * type. + */ + + nxagentSetDeferLevel(); + + /* + * Also set the display output buffer size. + */ + + nxagentSetBufferSize(); + + /* + * Select the preferred scheduler. + */ + + nxagentSetScheduler(); + + /* + * Select the buffer coalescence timeout. + */ + + nxagentSetCoalescence(); + + /* + * Set the other defaults. + */ + + if (nxagentOption(Fullscreen) == UNDEFINED) + { + nxagentChangeOption(Fullscreen, False); + } + + if (nxagentOption(AllScreens) == UNDEFINED) + { + nxagentChangeOption(AllScreens, False); + } + + if (nxagentOption(Binder) == UNDEFINED) + { + nxagentChangeOption(Binder, False); + } + + if (nxagentOption(Rootless) == UNDEFINED) + { + nxagentChangeOption(Rootless, False); + } + + if (nxagentOption(Desktop) == UNDEFINED) + { + nxagentChangeOption(Desktop, True); + } + + /* + * The enableBackingStore flag is defined + * in window.c in the dix. + */ +/* +FIXME: In rootless mode the backing-store support is not functional yet. +*/ + if (nxagentOption(Rootless)) + { + enableBackingStore = 0; + } + else if (nxagentOption(BackingStore) == BackingStoreUndefined || + nxagentOption(BackingStore) == BackingStoreForce) + { + enableBackingStore = 1; + } + else if (nxagentOption(BackingStore) == BackingStoreNever) + { + enableBackingStore = 0; + } + + /* + * need to check if this was set on the + * command line as this has the priority + * over the option file. + */ + + if (nxagentRenderEnable == UNDEFINED) + { + nxagentRenderEnable = True; + } + + if (nxagentRenderEnable == True) + { + nxagentAlphaEnabled = True; + } + else + { + nxagentAlphaEnabled = False; + } + + if ((nxagentOption(Rootless) == 1) && nxagentOption(Xdmcp)) + { + FatalError("PANIC! Cannot start a XDMCP session in rootless mode.\n"); + } + + /* + * We enable server reset only for indirect + * XDMCP sessions. + */ + + if (nxagentOption(Reset) == True && nxagentMaxAllowedResets == 0) + { + #ifdef WARNING + fprintf(stderr, "nxagentPostProcessArgs: Disabling the server reset.\n"); + #endif + + nxagentChangeOption(Reset, False); + + dispatchExceptionAtReset = 0; + } + + /* + * We skip server reset by default. This should + * be equivalent to passing the -noreset option + * to a standard XFree86 server. + */ + + if (nxagentOption(Reset) == False) + { + #ifdef TEST + fprintf(stderr, "nxagentPostProcessArgs: Disabling dispatch of exception at server reset.\n"); + #endif + + dispatchExceptionAtReset = 0; + } + + /* + * Check if the user activated the auto-disconect + * feature. + */ + + if (nxagentOption(Timeout) > 0) + { + fprintf(stderr, "Info: Using auto-disconnect timeout of %d seconds.\n", + nxagentOption(Timeout)); + + nxagentAutoDisconnectTimeout = nxagentOption(Timeout) * MILLI_PER_SECOND; + } + + #ifdef WATCH + + fprintf(stderr, "nxagentPostProcessArgs: Watchpoint 3.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +#16 1 256 bits (0 KB) -> 12 bits (0 KB) -> 256/1 -> 12/1 = 21.333:1 +#233 A 1 256 bits (0 KB) -> 131 bits (0 KB) -> 256/1 -> 131/1 = 1.954:1 +#245 A 2 512 bits (0 KB) -> 19 bits (0 KB) -> 256/1 -> 10/1 = 26.947:1 +*/ + + sleep(30); + + #endif + + return useNXTrans; +} + +void ddxUseMsg() +{ + ErrorF("-display string display name of the real server\n"); + ErrorF("-sync synchronize with the real server\n"); + ErrorF("-full utilize full regeneration\n"); + ErrorF("-class string default visual class\n"); + ErrorF("-depth int default depth\n"); + ErrorF("-geometry WxH+X+Y window size and position\n"); + ErrorF("-bw int window border width\n"); + ErrorF("-name string window name\n"); + ErrorF("-scrns int number of screens to generate\n"); + ErrorF("-install install colormaps directly\n"); + + ErrorF("The NX system adds the following arguments:\n"); + ErrorF("-forcenx force use of NX protocol messages assuming communication through nxproxy\n"); + ErrorF("-timeout int auto-disconnect timeout in seconds (minimum allowed: 60)\n"); + ErrorF("-norootlessexit don't exit if there are no clients in rootless mode\n"); +#ifdef RENDER + ErrorF("-norender disable the use of the render extension\n"); + ErrorF("-nocomposite disable the use of the composite extension\n"); +#endif + ErrorF("-nopersistent disable disconnection/reconnection to the X display on SIGHUP\n"); + ErrorF("-noshmem disable use of shared memory extension\n"); + ErrorF("-shmem enable use of shared memory extension\n"); + ErrorF("-noshpix disable use of shared pixmaps\n"); + ErrorF("-shpix enable use of shared pixmaps\n"); + ErrorF("-noignore don't ignore pointer and keyboard configuration changes mandated by clients\n"); + ErrorF("-nokbreset don't reset keyboard device if the session is resumed\n"); + ErrorF("-noxkblock always allow applications to change layout through XKEYBOARD\n"); + ErrorF("-tile WxH size of image tiles (minimum allowed: 32x32)\n"); + ErrorF("-keystrokefile file file with keyboard shortcut definitions\n"); + ErrorF("-verbose print more warning and error messages\n"); + ErrorF("-D enable desktop mode\n"); + ErrorF("-R enable rootless mode\n"); + ErrorF("-S enable shadow mode\n"); + ErrorF("-B enable proxy binding mode\n"); +} + +static int nxagentGetDialogName() +{ + strcpy(nxagentDialogName, "NX"); + + *(nxagentDialogName + 255) = '\0'; + + if (*nxagentSessionId != '\0') + { + int length = strlen(nxagentSessionId); + + strcpy(nxagentDialogName, "NX - "); + + if (length > (MD5_LENGTH * 2 + 1) && + *(nxagentSessionId + (length - (MD5_LENGTH * 2 + 1))) == '-') + { + strncat(nxagentDialogName, nxagentSessionId, length - (MD5_LENGTH * 2 + 1)); + } + else + { + strncat(nxagentDialogName, nxagentSessionId, 250); + } + + *(nxagentSessionId + 255) = '\0'; + + return 1; + } + + return 0; +} + +void nxagentSetPackMethod(void) +{ + unsigned char supportedMethods[NXNumberOfPackMethods]; + unsigned int entries = NXNumberOfPackMethods; + + int method; + + if (nxagentOption(LinkType) == LINK_TYPE_NONE) + { + nxagentChangeOption(Streaming, 0); + + nxagentPackMethod = PACK_NONE; + nxagentPackLossless = PACK_NONE; + + nxagentSplitThreshold = 0; + + return; + } + + /* + * Check if we need to select the lossy + * and lossless pack methods based on + * the link type. + */ + + method = nxagentPackMethod; + + if (method == PACK_ADAPTIVE) + { + #ifdef TEST + fprintf(stderr, "nxagentSetPackMethod: Using adaptive mode for image compression.\n"); + #endif + + nxagentChangeOption(Adaptive, 1); + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentSetPackMethod: Not using adaptive mode for image compression.\n"); + #endif + + nxagentChangeOption(Adaptive, 0); + } + + if (method == PACK_LOSSY || method == PACK_ADAPTIVE) + { + nxagentPackMethod = PACK_JPEG_16M_COLORS; + } + else if (method == PACK_LOSSLESS) + { + switch (nxagentOption(LinkType)) + { + case LINK_TYPE_MODEM: + case LINK_TYPE_ISDN: + case LINK_TYPE_ADSL: + case LINK_TYPE_WAN: + { + nxagentPackMethod = PACK_BITMAP_16M_COLORS; + + break; + } + case LINK_TYPE_LAN: + { + nxagentPackMethod = PACK_RLE_16M_COLORS; + + break; + } + default: + { + fprintf(stderr, "Warning: Unknown link type '%d' while setting the pack method.\n", + nxagentOption(LinkType)); + + break; + } + } + } + + /* + * Query the remote proxy to determine + * whether the selected methods are + * supported. + */ + + if (NXGetUnpackParameters(nxagentDisplay, &entries, supportedMethods) == 0 || + entries != NXNumberOfPackMethods) + { + fprintf(stderr, "Warning: Unable to retrieve the supported pack methods.\n"); + + nxagentPackMethod = PACK_NONE; + nxagentPackLossless = PACK_NONE; + } + else + { + if (nxagentPackMethod == PACK_BITMAP_16M_COLORS || + nxagentPackMethod == PACK_RLE_16M_COLORS || + nxagentPackMethod == PACK_RGB_16M_COLORS || + nxagentPackMethod == PACK_NONE) + { + nxagentPackLossless = nxagentPackMethod; + } + else + { + if (nxagentOption(LinkType) == LINK_TYPE_LAN) + { + nxagentPackLossless = PACK_RLE_16M_COLORS; + } + else + { + nxagentPackLossless = PACK_BITMAP_16M_COLORS; + } + } + + if (supportedMethods[nxagentPackLossless] == 0) + { + nxagentPackLossless = PACK_NONE; + } + + #ifdef TEST + fprintf(stderr, "nxagentSetPackMethod: Using method [%d] for lossless compression.\n", + nxagentPackLossless); + #endif + + if (supportedMethods[nxagentPackMethod] == 0) + { + fprintf(stderr, "Warning: Pack method '%d' not supported by the proxy.\n", + nxagentPackMethod); + + fprintf(stderr, "Warning: Replacing with lossless pack method '%d'.\n", + nxagentPackLossless); + + nxagentPackMethod = nxagentPackLossless; + } + } + + if (nxagentPackMethod == nxagentPackLossless) + { + nxagentPackQuality = 9; + } + + #ifdef TEST + fprintf(stderr, "nxagentSetPackMethod: Assuming pack methods [%d] and [%d] with " + "quality [%d].\n", nxagentPackMethod, nxagentPackLossless, nxagentPackQuality); + #endif +} + +/* + * Each defer level adds the following rules to the previous ones: + * + * Level 0 Eager encoding. + * + * Level 1 No data is put or copied on pixmaps, marking them always + * as corrupted and synchronizing them on demand, i.e. when + * a copy area to a window is requested, the source is syn- + * chronized before copying it. + * + * Level 2 The put images over the windows are skipped marking the + * destination as corrupted. The same happens for copy area + * and composite operations, spreading the corrupted regions + * of involved drawables. + */ + +void nxagentSetDeferLevel() +{ + int deferLevel; + int tileWidth; + int tileHeight; + int deferTimeout; + + /* + * Streaming is only partly implemented + * and is not available in this version + * of the agent. + */ + + if (nxagentOption(Streaming) == 1) + { + fprintf(stderr, "Warning: Streaming of images not available in this agent.\n"); + + nxagentChangeOption(Streaming, 0); + } + + switch (nxagentOption(LinkType)) + { + case LINK_TYPE_MODEM: + { + deferLevel = 2; + + tileWidth = 64; + tileHeight = 64; + + deferTimeout = 200; + + break; + } + case LINK_TYPE_ISDN: + { + deferLevel = 2; + + tileWidth = 64; + tileHeight = 64; + + deferTimeout = 200; + + break; + } + case LINK_TYPE_ADSL: + { + deferLevel = 2; + + deferTimeout = 200; + + tileWidth = 4096; + tileHeight = 4096; + + break; + } + case LINK_TYPE_WAN: + { + deferLevel = 1; + + deferTimeout = 200; + + tileWidth = 4096; + tileHeight = 4096; + + break; + } + case LINK_TYPE_NONE: + case LINK_TYPE_LAN: + { + deferLevel = 0; + + deferTimeout = 200; + + tileWidth = 4096; + tileHeight = 4096; + + break; + } + default: + { + fprintf(stderr, "Warning: Unknown link type [%d] processing the defer option.\n", + nxagentOption(LinkType)); + + deferLevel = 0; + + tileWidth = 64; + tileHeight = 64; + + deferTimeout = 200; + + break; + } + } + + /* + * Set the defer timeout. + */ + + if (nxagentOption(Shadow) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSetDeferLevel: Ignoring defer timeout parameter in shadow mode.\n"); + #endif + } + else + { + nxagentChangeOption(DeferTimeout, deferTimeout); + } + + /* + * Set the defer level. + */ + + if (nxagentOption(Shadow) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSetDeferLevel: Ignoring defer parameter in shadow mode.\n"); + #endif + } + else if (nxagentOption(DeferLevel) != UNDEFINED) + { + #ifdef TEST + fprintf(stderr, "nxagentSetDeferLevel: Not overriding the [defer] option " + "with value [%d]. Defer timeout is [%ld] ms.\n", nxagentOption(DeferLevel), + nxagentOption(DeferTimeout)); + #endif + } + else + { + nxagentChangeOption(DeferLevel, deferLevel); + + #ifdef TEST + fprintf(stderr, "nxagentSetDeferLevel: Assuming defer level [%d] with timeout of [%ld] ms.\n", + nxagentOption(DeferLevel), nxagentOption(DeferTimeout)); + #endif + } + + /* + * Set the tile width. + */ + + if (nxagentOption(TileWidth) != UNDEFINED) + { + #ifdef TEST + fprintf(stderr, "nxagentSetDeferLevel: Not overriding the [tile] option " + "width value [%d].\n", nxagentOption(TileWidth)); + #endif + } + else + { + nxagentChangeOption(TileWidth, tileWidth); + + #ifdef TEST + fprintf(stderr, "nxagentSetDeferLevel: Assuming tile width [%d].\n", + nxagentOption(TileWidth)); + #endif + } + + /* + * Set the tile height. + */ + + if (nxagentOption(TileHeight) != UNDEFINED) + { + #ifdef TEST + fprintf(stderr, "nxagentSetDeferLevel: Not overriding the [tile] option " + "height value [%d].\n", nxagentOption(TileHeight)); + #endif + } + else + { + nxagentChangeOption(TileHeight, tileHeight); + + #ifdef TEST + fprintf(stderr, "nxagentSetDeferLevel: Assuming tile height [%d].\n", + nxagentOption(TileHeight)); + #endif + } +} + +void nxagentSetBufferSize() +{ + int size; + + switch (nxagentOption(LinkType)) + { + case LINK_TYPE_MODEM: + { + size = 4096; + + break; + } + case LINK_TYPE_ISDN: + { + size = 4096; + + break; + } + case LINK_TYPE_ADSL: + { + size = 8192; + + break; + } + case LINK_TYPE_WAN: + { + size = 16384; + + break; + } + case LINK_TYPE_NONE: + case LINK_TYPE_LAN: + { + size = 16384; + + break; + } + default: + { + fprintf(stderr, "Warning: Unknown link type '%d' while setting the display buffer size.\n", + nxagentOption(LinkType)); + + size = 16384; + + break; + } + } + + nxagentChangeOption(DisplayBuffer, size); + + nxagentBuffer = size; + + if (NXSetDisplayBuffer(nxagentDisplay, nxagentBuffer) < 0) + { + fprintf(stderr, "Warning: Can't set the display buffer size to [%d].\n", + nxagentBuffer); + } +} + +void nxagentSetScheduler() +{ + /* + * The smart scheduler is the default. + */ + + if (nxagentOption(Shadow) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSetScheduler: Using the dumb scheduler in shadow mode.\n"); + #endif + + nxagentDisableTimer(); + } +} + +void nxagentSetCoalescence() +{ + int timeout; + + switch (nxagentOption(LinkType)) + { + case LINK_TYPE_MODEM: + { + timeout = 50; + + break; + } + case LINK_TYPE_ISDN: + { + timeout = 20; + + break; + } + case LINK_TYPE_ADSL: + { + timeout = 10; + + break; + } + case LINK_TYPE_WAN: + { + timeout = 5; + + break; + } + case LINK_TYPE_NONE: + case LINK_TYPE_LAN: + { + timeout = 0; + + break; + } + default: + { + fprintf(stderr, "Warning: Unknown link type '%d' while setting the display coalescence.\n", + nxagentOption(LinkType)); + + timeout = 0; + + break; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentSetCoalescence: Using coalescence timeout of [%d] ms.\n", + timeout); + #endif + + nxagentChangeOption(DisplayCoalescence, timeout); +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Args.h b/nx-X11/programs/Xserver/hw/nxagent/Args.h new file mode 100644 index 000000000..5192783e5 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Args.h @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Args_H__ +#define __Args_H__ + +#define MD5_LENGTH 16 + +struct UserGeometry{ + int flag; + int X; + int Y; + unsigned int Width; + unsigned int Height; +}; + +extern Bool nxagentUseNXTrans; + +extern char nxagentSessionId[]; +extern char nxagentDisplayName[]; +extern char nxagentShadowDisplayName[]; +extern char nxagentWindowName[]; +extern char nxagentDialogName[]; + +extern Bool nxagentSynchronize; +extern Bool nxagentFullGeneration; +extern int nxagentDefaultClass; +extern Bool nxagentUserDefaultClass; +extern int nxagentDefaultDepth; +extern Bool nxagentUserDefaultDepth; +extern int nxagentX; +extern int nxagentY; +extern unsigned int nxagentWidth; +extern unsigned int nxagentHeight; +extern struct UserGeometry nxagentUserGeometry; +extern Bool nxagentUserBorderWidth; +extern int nxagentNumScreens; +extern Bool nxagentDoDirectColormaps; +extern Window nxagentParentWindow; +extern int nxagentMaxAllowedReset; +extern Bool nxagentResizeDesktopAtStartup; +extern Bool nxagentIpaq; + +extern int nxagentLockDeferLevel; + +Bool nxagentPostProcessArgs(char *name, Display *dpy, Screen *scr); +void nxagentProcessOptionsFile(void); + +void nxagentSetPackMethod(void); +void nxagentSetDeferLevel(void); +void nxagentSetBufferSize(void); +void nxagentSetScheduler(void); +void nxagentSetCoalescence(void); + +extern int nxagentUserDefinedFontPath; + +extern int nxagentRemoteMajor; + +extern char *nxagentKeystrokeFile; + +#endif /* __Args_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Atoms.c b/nx-X11/programs/Xserver/hw/nxagent/Atoms.c new file mode 100644 index 000000000..0784d6c2c --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Atoms.c @@ -0,0 +1,796 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "scrnintstr.h" +#include "Agent.h" + +#include "Xutil.h" +#include "Xatom.h" +#include "Xlib.h" + +#include "misc.h" +#include "scrnintstr.h" +#include "resource.h" + +#include <nx/NXpack.h> + +#include "Atoms.h" +#include "Args.h" +#include "Image.h" +#include "Display.h" +#include "Screen.h" +#include "Options.h" +#include "Agent.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * These values should be moved in + * the option repository. + */ + +Bool nxagentWMIsRunning; + +static void startWMDetection(void); + +static int nxagentInitAtomMap(char **atomNameList, int count, Atom *atomsRet); + +#ifdef DEBUG +static void nxagentPrintAtomMapInfo(char *message); +#else +#define nxagentPrintAtomMapInfo(arg) +#endif + +Atom nxagentAtoms[NXAGENT_NUMBER_OF_ATOMS]; + +static char *nxagentAtomNames[NXAGENT_NUMBER_OF_ATOMS + 1] = +{ + "NX_IDENTITY", /* 0 */ + "WM_PROTOCOLS", /* 1 */ + "WM_DELETE_WINDOW", /* 2 */ + "WM_NX_READY", /* 3 */ + "MCOPGLOBALS", /* 4 */ + "NX_CUT_BUFFER_SERVER", /* 5 */ + "TARGETS", /* 6 */ + "TEXT", /* 7 */ + "NX_AGENT_SIGNATURE", /* 8 */ + "NXDARWIN", /* 9 */ + "CLIPBOARD", /* 10 */ + "TIMESTAMP", /* 11 */ + "UTF8_STRING", /* 12 */ + "_NET_WM_STATE", /* 13 */ + "_NET_WM_STATE_FULLSCREEN", /* 14 */ + NULL, + NULL +}; + +static XErrorHandler previousErrorHandler = NULL; + +static void catchAndRedirect(Display* dpy, XErrorEvent* X) +{ + if (X -> error_code == BadAccess && + X -> request_code == X_ChangeWindowAttributes && + X -> resourceid == DefaultRootWindow(dpy)) + { + nxagentWMIsRunning = TRUE; + } + else + { + previousErrorHandler(dpy, X); + } +} + +static void startWMDetection() +{ + /* + * We are trying to detect if is there any client + * that is listening for 'WM' events on the root + * window. + */ + + nxagentWMIsRunning = FALSE; + + previousErrorHandler = XSetErrorHandler((XErrorHandler)&catchAndRedirect); + + /* + * After this request we need to Sync with + * the X server to be sure we get any error + * that is generated. + */ + + XSelectInput(nxagentDisplay, + RootWindow (nxagentDisplay, 0), + SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask); +} + +static void finishWMDetection(Bool verbose) +{ + XSetErrorHandler(previousErrorHandler); + + if (nxagentWMIsRunning) + { + if (verbose == 1) + { + fprintf(stderr, "Info: Detected window manager running.\n"); + } + } + else + { + if (verbose == 1) + { + fprintf(stderr, "Info: Not found a window manager running.\n"); + } + + /* + * We are not really interested on root window events. + */ + + XSelectInput(nxagentDisplay, RootWindow (nxagentDisplay, 0), 0); + } +} + +void nxagentWMDetect() +{ + Bool verbose = False; + int windowManagerWasRunning = nxagentWMIsRunning; + + startWMDetection(); + + XSync(nxagentDisplay, 0); + + if (windowManagerWasRunning != nxagentWMIsRunning) + { + verbose = False; + } + + finishWMDetection(verbose); +} + +int nxagentInitAtoms(WindowPtr pWin) +{ + Atom atom; + + /* + * Value of nxagentAtoms[8] is "NX_AGENT_SIGNATURE". + * + * We don't need to save the atom's value. It will + * be checked by other agents to find if they are + * run nested. + */ + + atom = MakeAtom(nxagentAtomNames[8], strlen(nxagentAtomNames[8]), 1); + + if (atom == None) + { + #ifdef PANIC + fprintf(stderr, "nxagentInitAtoms: PANIC! Could not create [%s] atom.\n", + nxagentAtomNames[8]); + #endif + + return -1; + } + + return 1; +} + +int nxagentQueryAtoms(ScreenPtr pScreen) +{ + int i; + static unsigned long atomGeneration = 1; + + int num_of_atoms = NXAGENT_NUMBER_OF_ATOMS; + char *names[NXAGENT_NUMBER_OF_ATOMS]; + + unsigned long int startingTime = GetTimeInMillis(); + + #ifdef TEST + fprintf(stderr, "nxagentQueryAtoms: Going to create the intern atoms on real display.\n"); + + fprintf(stderr, "nxagentQueryAtoms: Starting time is [%ld].\n", startingTime); + #endif + + nxagentPrintAtomMapInfo("nxagentQueryAtoms: Entering"); + + for (i = 0; i < num_of_atoms; i++) + { + names[i] = nxagentAtomNames[i]; + + nxagentAtoms[i] = None; + } + + if (nxagentSessionId[0]) + { + names[num_of_atoms - 1] = nxagentSessionId; + } + else + { + num_of_atoms--; + } + + startWMDetection(); + + nxagentInitAtomMap(names, num_of_atoms, nxagentAtoms); + + /* + * We need to be synchronized with the X server + * in order to detect the Window Manager, since + * after a reset the XInternAtom could be cached + * by Xlib. + */ + + if (atomGeneration != serverGeneration) + { + #ifdef WARNING + fprintf(stderr, "nxagentQueryAtoms: The nxagent has been reset with server %ld atom %ld.\n", + serverGeneration, atomGeneration); + + fprintf(stderr, "nxagentQueryAtoms: Forcing a sync to detect the window manager.\n"); + #endif + + atomGeneration = serverGeneration; + + XSync(nxagentDisplay, 0); + } + + finishWMDetection(False); + + /* + * Value of nxagentAtoms[9] is "NXDARWIN". + * + * We check if it was created by the NX client. + */ + + if (nxagentAtoms[9] > nxagentAtoms[0]) + { + nxagentAtoms[9] = None; + } + + /* + * Value of nxagentAtoms[8] is "NX_AGENT_SIGNATURE". + * + * This atom is created internally by the agent server at + * startup to let other agents determine if they are run + * nested. If agent is run nested, in fact, at the time it + * will create the NX_AGENT_SIGNATURE atom on the real X + * server it will find the existing atom with a value less + * than any NX_IDENTITY created but itself. + */ + + if (nxagentAtoms[8] > nxagentAtoms[0]) + { + nxagentAtoms[8] = None; + } + + if (nxagentAtoms[8] != None) + { + /* + * We are running nested in another agent + * server. + */ + + nxagentChangeOption(Nested, 1); + + /* + * Avoid the image degradation caused by + * multiple lossy encoding. + */ + + fprintf(stderr, "Warning: Disabling use of lossy encoding in nested mode.\n"); + + nxagentPackMethod = nxagentPackLossless; + } + + #ifdef TEST + + for (i = 0; i < num_of_atoms; i++) + { + fprintf(stderr, "nxagentQueryAtoms: Created intern atom [%s] with id [%ld].\n", + names[i], nxagentAtoms[i]); + } + + #endif + + nxagentChangeOption(DisplayLatency, GetTimeInMillis() - startingTime); + + #ifdef TEST + fprintf(stderr, "nxagentQueryAtoms: Ending time is [%ld] reference latency is [%d] Ms.\n", + GetTimeInMillis(), nxagentOption(DisplayLatency)); + #endif + + nxagentPrintAtomMapInfo("nxagentQueryAtoms: Exiting"); + + return 1; +} + +#define NXAGENT_ATOM_MAP_SIZE_INCREMENT 256 + +typedef struct { + Atom local; + Atom remote; + const char *string; + int length; +} AtomMap; + +static AtomMap *privAtomMap = NULL; +static unsigned int privAtomMapSize = 0; +static unsigned int privLastAtom = 0; + +static void nxagentExpandCache(void); +static void nxagentWriteAtom(Atom, Atom, const char*, Bool); +static AtomMap* nxagentFindAtomByRemoteValue(Atom); +static AtomMap* nxagentFindAtomByLocalValue(Atom); +static AtomMap* nxagentFindAtomByName(char*, unsigned); + +static void nxagentExpandCache(void) +{ + privAtomMapSize += NXAGENT_ATOM_MAP_SIZE_INCREMENT; + + privAtomMap = realloc(privAtomMap, privAtomMapSize * sizeof(AtomMap)); + + if (privAtomMap == NULL) + { + FatalError("nxagentExpandCache: realloc failed\n"); + } +} + +/* + * Check if there is space left on the map + * and manage the possible consequent allocation, + * then cache the atom-couple. + */ + +static void nxagentWriteAtom(Atom local, Atom remote, const char *string, Bool duplicate) +{ + const char *s; + + /* + * We could remove this string duplication if + * we know for sure that the server will not + * reset, since only at reset the dix layer + * free all the atom names. + */ + + if (duplicate) + { + s = strdup(string); + + #ifdef WARNING + if (s == NULL) + { + fprintf(stderr, "nxagentWriteAtom: Malloc failed.\n"); + } + #endif + } + else + { + s = string; + } + + if (privLastAtom == privAtomMapSize) + { + nxagentExpandCache(); + } + + privAtomMap[privLastAtom].local = local; + privAtomMap[privLastAtom].remote = remote; + privAtomMap[privLastAtom].string = s; + privAtomMap[privLastAtom].length = strlen(s); + + privLastAtom++; +} + +/* + * FIXME: We should clean up the atom map + * at nxagent reset, in order to cancel + * all the local atoms but still mantaining + * the Xserver values and the atom names. + */ + +void nxagentResetAtomMap() +{ + unsigned i; + + nxagentPrintAtomMapInfo("nxagentResetAtomMap: Entering"); + + for (i = 0; i < privLastAtom; i++) + { + privAtomMap[i].local = None; + } + + nxagentPrintAtomMapInfo("nxagentResetAtomMap: Exiting"); +} + +/* + * Init map. + * Initializing the atomNameList all in one. + */ + +static int nxagentInitAtomMap(char **atomNameList, int count, Atom *atomsRet) +{ + XlibAtom *atom_list; + char **name_list; + unsigned int i; + int ret_value = 0; + int list_size = count + privLastAtom; + + nxagentPrintAtomMapInfo("nxagentInitAtomMap: Entering"); + + atom_list = malloc((list_size) * sizeof(*atom_list)); + name_list = malloc((list_size) * sizeof(char*)); + + if ((atom_list == NULL) || (name_list == NULL)) + { + FatalError("nxagentInitAtomMap: malloc failed\n"); + } + + for (i = 0; i < count; i++) + { + name_list[i] = atomNameList[i]; + atom_list[i] = None; + } + + for (i = 0; i < privLastAtom; i++) + { + name_list[count + i] = (char *)privAtomMap[i].string; + atom_list[count + i] = None; + } + + /* + * Ask X-Server for ours Atoms + * ... if successfull cache them too. + */ + + ret_value = XInternAtoms(nxagentDisplay, name_list, list_size, False, atom_list); + + if (ret_value == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentInitAtomMap: WARNING! XInternAtoms request failed.\n"); + #endif + + free(atom_list); + free(name_list); + + return 0; + } + + for (i = 0; i < list_size; i++) + { + AtomMap *aMap = nxagentFindAtomByName(name_list[i], strlen(name_list[i])); + + if (aMap == NULL) + { + Atom local = MakeAtom(name_list[i], strlen(name_list[i]), True); + + if (ValidAtom(local)) + { + nxagentWriteAtom(local, atom_list[i], name_list[i], False); + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentInitAtomMap: WARNING MakeAtom failed.\n"); + #endif + } + } + else + { + aMap -> remote = atom_list[i]; + + if (i < count && aMap -> local == None) + { + aMap -> local = MakeAtom(name_list[i], strlen(name_list[i]), True); + } + } + + if (i < count) + { + atomsRet[i] = atom_list[i]; + } + } + + free(atom_list); + free(name_list); + + nxagentPrintAtomMapInfo("nxagentInitAtomMap: Exiting"); + + return 1; +} + +/* + * If the nxagent has been resetted, + * the local value of the atoms stored + * in cache could have the value None, + * do not call this function with None. + */ + +static AtomMap* nxagentFindAtomByLocalValue(Atom local) +{ + unsigned i; + + if (!ValidAtom(local)) + { + return NULL; + } + + for (i = 0; i < privLastAtom; i++) + { + if (local == privAtomMap[i].local) + { + return (privAtomMap + i); + } + } + + return NULL; +} + +static AtomMap* nxagentFindAtomByRemoteValue(Atom remote) +{ + unsigned i; + + if (remote == None || remote == BAD_RESOURCE) + { + return NULL; + } + + for (i = 0; i < privLastAtom; i++) + { + if (remote == privAtomMap[i].remote) + { + return (privAtomMap + i); + } + } + + return NULL; +} + +static AtomMap* nxagentFindAtomByName(char *string, unsigned int length) +{ + unsigned i; + + for (i = 0; i < privLastAtom; i++) + { + if ((length == privAtomMap[i].length) && + (strcmp(string, privAtomMap[i].string) == 0)) + { + return (privAtomMap + i); + } + } + + return NULL; +} + +/* + * Convert local atom's name to X-server value. + * Reading them from map, if they have been already cached or + * really asking to X-server and caching them. + * FIXME: I don't really know if is better to allocate + * an automatic variable like ret_value and write it, instead of make all + * these return!, perhaps this way the code is a little bit easyer to read. + * I think this and the 2 .*Find.* are the only functions to look for performances. + */ + +Atom nxagentMakeAtom(char *string, unsigned int length, Bool Makeit) +{ + Atom local; + AtomMap *current; + + /* + * Surely MakeAtom is faster than + * our nxagentFindAtomByName. + */ + + local = MakeAtom(string, length, Makeit); + + if (!ValidAtom(local)) + { + return None; + } + + if (local <= XA_LAST_PREDEFINED) + { + return local; + } + + if ((current = nxagentFindAtomByLocalValue(local))) + { + /* + * Found cached by value. + */ + + return current->remote; + } + + if ((current = nxagentFindAtomByName(string, length))) + { + /* + * Found Cached by name. + * It means that nxagent has been resetted, + * but not the xserver so we still have cached its atoms. + */ + + current->local = local; + + return current->remote; + } + + /* + * We really have to ask Xserver for it. + */ + + { + Atom remote; + + remote = XInternAtom(nxagentDisplay, string, !Makeit); + + if (remote == None) + { + #ifdef WARNING + fprintf(stderr, "nxagentMakeAtom: WARNING XInternAtom failed.\n"); + #endif + + return None; + } + + nxagentWriteAtom(local, remote, string, True); + + return remote; + } +} + +Atom nxagentLocalToRemoteAtom(Atom local) +{ + AtomMap *current; + const char *string; + Atom remote; + + if (!ValidAtom(local)) + { + return None; + } + + if (local <= XA_LAST_PREDEFINED) + { + return local; + } + + if ((current = nxagentFindAtomByLocalValue(local))) + { + return current->remote; + } + + string = NameForAtom(local); + + remote = XInternAtom(nxagentDisplay, string, False); + + if (remote == None) + { + #ifdef WARNING + fprintf(stderr, "nxagentLocalToRemoteAtom: WARNING XInternAtom failed.\n"); + #endif + + return None; + } + + nxagentWriteAtom(local, remote, string, True); + + return remote; +} + +Atom nxagentRemoteToLocalAtom(Atom remote) +{ + AtomMap *current; + char *string; + Atom local; + + if (remote == None || remote == BAD_RESOURCE) + { + return None; + } + + if (remote <= XA_LAST_PREDEFINED) + { + return remote; + } + + if ((current = nxagentFindAtomByRemoteValue(remote))) + { + if (!ValidAtom(current->local)) + { + local = MakeAtom(current->string, current->length, True); + + if (ValidAtom(local)) + { + current->local = local; + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentRemoteToLocalAtom: WARNING MakeAtom failed.\n"); + #endif + + current->local = None; + } + } + + return current->local; + } + + if ((string = XGetAtomName(nxagentDisplay, remote))) + { + local = MakeAtom(string, strlen(string), True); + + if (!ValidAtom(local)) + { + #ifdef WARNING + fprintf(stderr, "nxagentRemoteToLocalAtom: WARNING MakeAtom failed.\n"); + #endif + + local = None; + } + + nxagentWriteAtom(local, remote, string, True); + + XFree(string); + + return local; + } + + #ifdef WARNING + fprintf(stderr, "nxagentRemoteToLocalAtom: WARNING failed to get name from remote atom.\n"); + #endif + + return None; +} + +#ifdef DEBUG + +static void nxagentPrintAtomMapInfo(char *message) +{ + unsigned i; + + fprintf(stderr, "--------------- Atom map in context [%s] ----------------------\n", message); + fprintf(stderr, "nxagentPrintAtomMapInfo: Map at [%p] size [%d] number of entry [%d] auto increment [%d].\n", + (void*) privAtomMap, privLastAtom, privAtomMapSize, NXAGENT_ATOM_MAP_SIZE_INCREMENT); + + for (i = 0; i < privLastAtom; i++) + { + fprintf(stderr, "[%5.1d] local: %6.1lu - remote: %6.1lu - [%p] %s\n", i, + privAtomMap[i].local, + privAtomMap[i].remote, + privAtomMap[i].string, validateString(privAtomMap[i].string)); + } + + fprintf(stderr, "---------------------------------------------\n"); +} + +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/Atoms.h b/nx-X11/programs/Xserver/hw/nxagent/Atoms.h new file mode 100644 index 000000000..391e06181 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Atoms.h @@ -0,0 +1,73 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Atoms_H__ +#define __Atoms_H__ + +#include "X.h" +#include "../../include/window.h" +#include "screenint.h" + +#define NXAGENT_NUMBER_OF_ATOMS 16 + +extern Atom nxagentAtoms[NXAGENT_NUMBER_OF_ATOMS]; + +extern Bool nxagentWMIsRunning; + +/* + * Create the required atoms internally + * to the agent server. + */ + +int nxagentInitAtoms(WindowPtr pWin); + +/* + * Query and create all the required atoms + * on the remote X server using a single + * round trip. + */ + +int nxagentQueryAtoms(ScreenPtr pScreen); + +/* + * Create the atoms on the remote X server + * and cache the couple local-remote atoms. + */ + +Atom nxagentMakeAtom(char *, unsigned, Bool); + +/* + * Converts local atoms in remote atoms and + * viceversa. + */ + +Atom nxagentRemoteToLocalAtom(Atom); +Atom nxagentLocalToRemoteAtom(Atom); + +void nxagentResetAtomMap(void); + +void nxagentWMDetect(void); + +#endif /* __Atoms_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Binder.c b/nx-X11/programs/Xserver/hw/nxagent/Binder.c new file mode 100644 index 000000000..ae1cd0f25 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Binder.c @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <nx/NX.h> + +#include "Binder.h" +#include "Options.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int nxagentCheckBinder(int argc, char *argv[], int i) +{ + if (++i < argc) + { + char *display; + char *found; + + int port; + + display = argv[i]; + + /* + * Check if a display specification follows + * the -B switch. + */ + + found = rindex(display, ':'); + + if (found == NULL || *(found + 1) == '\0' || + isdigit(*(found + 1)) == 0) + { + fprintf(stderr, "Error: Can't identify the display port in string '%s'.\n", + display); + + return 0; + } + + port = atoi(found + 1); + + #ifdef TEST + fprintf(stderr, "nxagentCheckBinder: Identified agent display port [%d].\n", + port); + #endif + + /* + * The NX options must be specified in the DISPLAY + * environment. Check if the display specified on + * the command line matches the NX virtual display. + */ + + display = getenv("DISPLAY"); + + if (display == NULL || *display == '\0') + { + fprintf(stderr, "Error: No DISPLAY environment found.\n"); + + return 0; + } + + found = rindex(display, ':'); + + if (found == NULL || *(found + 1) == '\0' || + isdigit(*(found + 1)) == 0 || atoi(found + 1) != port) + { + fprintf(stderr, "Error: The NX display doesn't match the agent display :%d.\n", + port); + + return 0; + } + + #ifdef TEST + fprintf(stderr, "nxagentCheckBinder: Identified NX display port [%d].\n", + atoi(found + 1)); + #endif + + /* + * Save the proxy options. They will be later + * used to create the transport. + */ + + nxagentChangeOption(Rootless, False); + nxagentChangeOption(Desktop, False); + nxagentChangeOption(Binder, True); + + /* + * FIXME: This now points to the buffer that was + * returned by getenv(). It is to be decided how + * to handle the values of type string in the + * Options repository. + */ + + nxagentChangeOption(BinderOptions, display); + + return 2; + } + + fprintf(stderr, "Error: No display port specified in command.\n"); + + return 0; +} + +int nxagentBinderLoop() +{ + struct timeval timeout; + + char *options = nxagentOption(BinderOptions); + + #ifdef TEST + fprintf(stderr, "nxagentBinderLoop: Creating the NX transport.\n"); + #endif + + if (NXTransCreate(NX_FD_ANY, NX_MODE_CLIENT, options) < 0) + { + #ifdef TEST + fprintf(stderr, "nxagentBinderLoop: PANIC! Error creating the NX transport.\n"); + #endif + + return -1; + } + + #ifdef TEST + fprintf(stderr, "nxagentBinderLoop: Yielding control to the NX entry point.\n"); + #endif + + while (NXTransRunning(NX_FD_ANY)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentBinderLoop: Going to run a new NX proxy loop.\n"); + #endif + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + NXTransContinue(&timeout); + + #ifdef DEBUG + fprintf(stderr, "nxagentBinderLoop: Completed execution of the NX loop.\n"); + #endif + } + + #ifdef TEST + fprintf(stderr, "nxagentBinderLoop: Exiting the NX proxy binder loop.\n"); + #endif + + return 1; +} + +void nxagentBinderExit(int code) +{ + NXTransExit(code); +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Binder.h b/nx-X11/programs/Xserver/hw/nxagent/Binder.h new file mode 100644 index 000000000..fc6673132 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Binder.h @@ -0,0 +1,35 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Binder_H__ +#define __Binder_H__ + +int nxagentCheckBinder(int argc, char *argv[], int i); + +int nxagentBinderLoop(void); + +void nxagentBinderExit(int code); + +#endif /* __Binder_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/BitmapUtils.c b/nx-X11/programs/Xserver/hw/nxagent/BitmapUtils.c new file mode 100644 index 000000000..b889d2a62 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/BitmapUtils.c @@ -0,0 +1,118 @@ +/* + +Copyright 1990, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* + * Author: Keith Packard, MIT X Consortium + */ + +/* + * Derived from libXfont1's utilbitmap.c (available via fontmisc.h). + */ + +/* Utility functions for reformating font bitmaps */ + +static const unsigned char _reverse_byte[0x100] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +/* + * Invert bit order within each BYTE of an array. + */ +void +nxagentBitOrderInvert(unsigned char *buf, int nbytes) +{ + const unsigned char *rev = _reverse_byte; + + for (; --nbytes >= 0; buf++) + *buf = rev[*buf]; +} + +/* + * Invert byte order within each 16-bits of an array. + */ +void +nxagentTwoByteSwap(unsigned char *buf, int nbytes) +{ + unsigned char c; + + for (; nbytes > 0; nbytes -= 2, buf += 2) + { + c = buf[0]; + buf[0] = buf[1]; + buf[1] = c; + } +} + +/* + * Invert byte order within each 32-bits of an array. + */ +void +nxagentFourByteSwap(unsigned char *buf, int nbytes) +{ + unsigned char c; + + for (; nbytes > 0; nbytes -= 4, buf += 4) + { + c = buf[0]; + buf[0] = buf[3]; + buf[3] = c; + c = buf[1]; + buf[1] = buf[2]; + buf[2] = c; + } +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Client.c b/nx-X11/programs/Xserver/hw/nxagent/Client.c new file mode 100644 index 000000000..38d877ed7 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Client.c @@ -0,0 +1,546 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * Used in handling of karma on lost focus. + */ + +#include <signal.h> +#include <time.h> +#include <errno.h> + +#include <nx/NX.h> + +#include "Xatom.h" +#include "dixstruct.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "osdep.h" + +/* + * NX specific includes and definitions. + */ + +#include "Agent.h" +#include "Args.h" +#include "Display.h" +#include "Client.h" +#include "Dialog.h" +#include "Handlers.h" +#include "Events.h" +#include "Drawable.h" +#include "Utils.h" + +/* + * Need to include this after the stub + * definition of GC in Agent.h. + */ + +#include "compext/Compext.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Returns the last signal delivered + * to the process. + */ + +extern int _X11TransSocketCheckSignal(void); + +/* + * Time in milliseconds of first iteration + * through the dispatcher. + */ + +unsigned long nxagentStartTime = -1; + +/* + * If defined, add a function checking if we + * need a null timeout after a client wakeup. + */ + +#undef CHECK_RESTARTED_CLIENTS + +#ifdef CHECK_RESTARTED_CLIENTS + +void nxagentCheckRestartedClients(struct timeval **timeout); + +#endif + +/* + * Allow attaching private members to the client. + */ + +int nxagentClientPrivateIndex; + +/* + * The master nxagent holds in nxagentShadowCounter + * the number of shadow nxagents connected to itself. + */ + +int nxagentShadowCounter = 0; + +void nxagentInitClientPrivates(ClientPtr client) +{ + if (nxagentClientPriv(client)) + { + nxagentClientPriv(client) -> clientState = 0; + nxagentClientPriv(client) -> clientBytes = 0; + nxagentClientPriv(client) -> clientHint = UNKNOWN; + } +} + +/* + * Guess the running application based on the + * properties attached to its main window. + */ + +void nxagentGuessClientHint(ClientPtr client, Atom property, char *data) +{ + #ifdef TEST + fprintf(stderr, "++++++nxagentGuessClientHint: Client [%d] setting property [%s] as [%s].\n", + client -> index, validateString(NameForAtom(property)), validateString(data)); + #endif + + if (nxagentClientPriv(client) -> clientHint == UNKNOWN) + { + if (property == XA_WM_CLASS) + { + if (strcmp(data, "nxclient") == 0) + { + #ifdef TEST + fprintf(stderr, "++++++nxagentGuessClientHint: Detected nxclient as [%d].\n", client -> index); + #endif + + nxagentClientHint(client) = NXCLIENT_WINDOW; + } + else if (strstr(data, "java")) + { + #ifdef TEST + fprintf(stderr, "++++++nxagentGuessClientHint: Detected java as [%d].\n", client -> index); + #endif + + nxagentClientHint(client) = JAVA_WINDOW; + } + } + } + + if (nxagentClientPriv(client) -> clientHint == NXCLIENT_WINDOW) + { + if (property == MakeAtom("WM_WINDOW_ROLE", 14, True) && + strncmp(data, "msgBox", 6) == 0) + { + #ifdef TEST + fprintf(stderr, "++++++nxagentGuessClientHint: Detected nxclient dialog as [%d].\n", client -> index); + #endif + + nxagentClientHint(client) = NXCLIENT_DIALOG; + } + } +} + +void nxagentGuessShadowHint(ClientPtr client, Atom property) +{ + #ifdef DEBUG + fprintf(stderr, "nxagentGuessShadowHint: Client [%d] setting property [%s].\n", + client -> index, + validateString(NameForAtom(property))); + #endif + + if (nxagentClientPriv(client) -> clientHint == UNKNOWN) + { + if (strcmp(validateString(NameForAtom(property)), "_NX_SHADOW") == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentGuessShadowHint: nxagentShadowCounter [%d].\n", + nxagentShadowCounter); + + fprintf(stderr, "nxagentGuessShadowHint: Detected shadow nxagent as client [%d].\n", + client -> index); + + #endif + + nxagentClientHint(client) = NXAGENT_SHADOW; + + nxagentShadowCounter++; + + #ifdef TEST + fprintf(stderr, "nxagentGuessShadowHint: nxagentShadowCounter [%d].\n", + nxagentShadowCounter); + #endif + + /* + * From this moment on we ignore the visibility + * checks to keep the windows updated. + */ + + nxagentChangeOption(IgnoreVisibility, 1); + } + } +} + +void nxagentCheckIfShadowAgent(ClientPtr client) +{ + + if (nxagentClientPriv(client) -> clientHint == NXAGENT_SHADOW) + { + #ifdef TEST + fprintf(stderr, "nxagentCheckIfShadowAgent: nxagentShadowCounter [%d].\n", + nxagentShadowCounter); + + fprintf(stderr, "nxagentCheckIfShadowAgent: Shadow nxagent as client [%d] detached.\n", + client -> index); + + fprintf(stderr, "nxagentCheckIfShadowAgent: Decreasing nxagentShadowCounter.\n"); + #endif + + /* + * We decrease nxagentShadowCounter. + */ + + nxagentShadowCounter--; + + #ifdef TEST + fprintf(stderr, "nxagentCheckIfShadowAgent: nxagentShadowCounter [%d].\n", + nxagentShadowCounter); + #endif + + + if (nxagentShadowCounter == 0) + { + /* + * The last shadow nxagent has been detached + * from master nxagent. + * The master nxagent could do some action + * here. + */ + + #ifdef TEST + fprintf(stderr, "nxagentCheckIfShadowAgent: The last shadow nxagent has been detached.\n"); + #endif + + nxagentChangeOption(IgnoreVisibility, 0); + } + } +} + +void nxagentWakeupByReconnect() +{ + int i; + + #ifdef TEST + fprintf(stderr, "++++++nxagentWakeupByReconnect: Going to wakeup all clients.\n"); + #endif + + for (i = 1; i < currentMaxClients; i++) + { + if (clients[i] != NULL) + { + nxagentWakeupByReset(clients[i]); + } + } +} + +void nxagentWakeupByReset(ClientPtr client) +{ + #ifdef TEST + fprintf(stderr, "++++++nxagentWakeupByReset: Going to check client id [%d].\n", + client -> index); + #endif + + if (nxagentNeedWakeup(client)) + { + #ifdef TEST + fprintf(stderr, "++++++nxagentWakeupByReset: Going to wakeup client id [%d].\n", + client -> index); + #endif + + if (client -> index < MAX_CONNECTIONS) + { + if (nxagentNeedWakeupBySplit(client)) + { + nxagentWakeupBySplit(client); + } + } + } + + if (client -> index < MAX_CONNECTIONS) + { + #ifdef TEST + fprintf(stderr, "++++++nxagentWakeupByReset: Going to reset bytes received for client id [%d].\n", + client -> index); + #endif + + nxagentClientBytes(client) = 0; + } +} + +/* + * Wait for any event. + */ + +#define WAIT_ALL_EVENTS + +#ifndef WAIT_ALL_EVENTS + +static Bool nxagentWaitWakeupBySplitPredicate(Display *display, XEvent *event, XPointer ptr) +{ + return (event -> type == ClientMessage && + (event -> xclient.data.l[0] == NXNoSplitNotify || + event -> xclient.data.l[0] == NXStartSplitNotify || + event -> xclient.data.l[0] == NXCommitSplitNotify || + event -> xclient.data.l[0] == NXEndSplitNotify || + event -> xclient.data.l[0] == NXEmptySplitNotify) && + event -> xclient.window == 0 && event -> xclient.message_type == 0 && + event -> xclient.format == 32); +} + +#endif + +#define USE_FINISH_SPLIT + +void nxagentWaitWakeupBySplit(ClientPtr client) +{ + #ifdef TEST + + if (nxagentNeedWakeupBySplit(client) == 0) + { + fprintf(stderr, "++++++nxagentWaitWakeupBySplit: WARNING! The client [%d] is already awake.\n", + client -> index); + } + + fprintf(stderr, "++++++nxagentWaitWakeupBySplit: Going to wait for the client [%d].\n", + client -> index); + #endif + + /* + * Be sure we intercept an I/O error + * as well as an interrupt. + */ + + #ifdef USE_FINISH_SPLIT + + NXFinishSplit(nxagentDisplay, client -> index); + + #endif + + NXFlushDisplay(nxagentDisplay, NXFlushBuffer); + + for (;;) + { + /* + * Can we handle all the possible events here + * or we need to select only the split events? + * Handling all the possible events would pre- + * empt the queue and make a better use of the + * link. + */ + + #ifdef WAIT_ALL_EVENTS + + nxagentDispatchEvents(NULL); + + #else + + nxagentDispatchEvents(nxagentWaitWakeupBySplitPredicate); + + #endif + + if (nxagentNeedWakeupBySplit(client) == 0 || + NXDisplayError(nxagentDisplay) == 1) + { + #ifdef TEST + + if (nxagentNeedWakeupBySplit(client) == 0) + { + fprintf(stderr, "++++++nxagentWaitWakeupBySplit: Client [%d] can now run.\n", + client -> index); + } + else + { + fprintf(stderr, "++++++nxagentWaitWakeupBySplit: WARNING! Display error " + "detected waiting for restart.\n"); + } + + #endif + + return; + } + + #ifdef TEST + fprintf(stderr, "++++++nxagentWaitWakeupBySplit: Yielding control to the NX transport.\n"); + #endif + + nxagentWaitEvents(nxagentDisplay, NULL); + } +} + +int nxagentSuspendBySplit(ClientPtr client) +{ +/* +FIXME: Should record a serial number for the client, so that + the client is not restarted because of an end of split + of a previous client with the same index. +*/ + if (client -> index < MAX_CONNECTIONS) + { + if (nxagentNeedWakeup(client) == 0) + { + #ifdef TEST + fprintf(stderr, "++++++nxagentSuspendBySplit: Suspending client [%d] with agent sequence [%ld].\n", + client -> index, NextRequest(nxagentDisplay) - 1); + #endif + + if (client -> clientGone == 0) + { + #ifdef TEST + fprintf(stderr, "++++++nxagentSuspendBySplit: Client [%d] suspended.\n", client -> index); + #endif + + IgnoreClient(client); + } + } + #ifdef TEST + else + { + fprintf(stderr, "++++++nxagentSuspendBySplit: WARNING! Client [%d] already ignored with state [%x].\n", + client -> index, nxagentClientPriv(client) -> clientState); + } + #endif + + nxagentClientPriv(client) -> clientState |= SleepingBySplit; + + return 1; + } + + #ifdef WARNING + fprintf(stderr, "++++++nxagentSuspendBySplit: WARNING! Invalid client [%d] provided to function.\n", + client -> index); + #endif + + return -1; +} + +int nxagentWakeupBySplit(ClientPtr client) +{ +/* +FIXME: Should record a serial number for the client, so that + the client is not restarted because of the end of the + split for a previous client with the same index. +*/ + if (client -> index < MAX_CONNECTIONS) + { + nxagentClientPriv(client) -> clientState &= ~SleepingBySplit; + + if (nxagentNeedWakeup(client) == 0) + { + #ifdef TEST + fprintf(stderr, "++++++nxagentWakeupBySplit: Resuming client [%d] with agent sequence [%ld].\n", + client -> index, NextRequest(nxagentDisplay) - 1); + #endif + + if (client -> clientGone == 0) + { + AttendClient(client); + } + } + #ifdef TEST + else + { + fprintf(stderr, "++++++nxagentWakeupBySplit: WARNING! Client [%d] still suspended with state [%x].\n", + client -> index, nxagentClientPriv(client) -> clientState); + } + #endif + + return 1; + } + + #ifdef WARNING + fprintf(stderr, "++++++nxagentWakeupBySplit: WARNING! Invalid client [%d] provided to function.\n", + client -> index); + #endif + + return -1; +} + +#ifdef CHECK_RESTARTED_CLIENTS + +void nxagentCheckRestartedClients(struct timeval **timeout) +{ + static struct timeval zero; + + int i; + + /* + * If any of the restarted clients had requests + * in input we'll need to enter the select with + * a null timeout, or we will block until any + * other client becomes available. + */ + + for (i = 1; i < currentMaxClients; i++) + { + if (clients[i] != NULL && clients[i] -> osPrivate != NULL && + nxagentNeedWakeup(clients[i]) == 0) + { + int fd = ((OsCommPtr) clients[i] -> osPrivate) -> fd; + + if (FD_ISSET(fd, &ClientsWithInput)) + { + #ifdef WARNING + fprintf(stderr, "nxagentBlockHandler: WARNING! Client [%d] with fd [%d] has input.\n", + clients[i] -> index, fd); + #endif + + #ifdef DEBUG + fprintf(stderr, "nxagentBlockHandler: Setting a null timeout with former timeout [%ld] Ms.\n", + (*timeout) -> tv_sec * 1000 + (*timeout) -> tv_usec / 1000); + #endif + + if (*timeout != NULL) + { + (*timeout) -> tv_sec = 0; + (*timeout) -> tv_usec = 0; + } + else + { + zero.tv_sec = 0; + zero.tv_usec = 0; + + *timeout = &zero; + } + } + } + } +} + +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/Client.h b/nx-X11/programs/Xserver/hw/nxagent/Client.h new file mode 100644 index 000000000..8f4f503ba --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Client.h @@ -0,0 +1,128 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Client_H__ +#define __Client_H__ + +#define MAX_CONNECTIONS 256 + +/* + * The master nxagent holds in nxagentShadowCounter + * the number of shadow nxagents connected to itself. + */ + +extern int nxagentShadowCounter; + +enum ClientHint +{ + UNKNOWN = 0, + NXCLIENT_WINDOW, + NXCLIENT_DIALOG, + NXAGENT_SHADOW, + JAVA_WINDOW +}; + +typedef struct _PrivClientRec +{ + int clientState; + long clientBytes; + enum ClientHint clientHint; + +} PrivClientRec; + +extern int nxagentClientPrivateIndex; + +#define nxagentClientPriv(pClient) \ + ((PrivClientRec *)((pClient)->devPrivates[nxagentClientPrivateIndex].ptr)) + +void nxagentInitClientPrivates(ClientPtr); + +#define nxagentClientAddBytes(pClient, size) \ + (nxagentClientPriv(pClient) -> clientBytes += (size)) + +#define nxagentClientBytes(pClient) \ + (nxagentClientPriv(pClient) -> clientBytes) + +#define nxagentClientHint(pClient) \ + (nxagentClientPriv(pClient) -> clientHint) + +#define nxagentClientIsDialog(pClient) \ + (nxagentClientHint(pClient) == NXCLIENT_DIALOG) + +/* + * The actual reason why the client + * is sleeping. + */ + +#define SleepingBySplit 1 + +#define nxagentNeedWakeup(client) \ + ((nxagentClientPriv(client) -> \ + clientState) != 0) + +#define nxagentNeedWakeupBySplit(client) \ + (((nxagentClientPriv(client) -> \ + clientState) & SleepingBySplit) != 0) + +void nxagentGuessClientHint(ClientPtr, Atom, char*); + +void nxagentGuessShadowHint(ClientPtr, Atom); + +void nxagentCheckIfShadowAgent(ClientPtr); + +/* + * Suspend or restart the agent's + * client. + */ + +int nxagentSuspendBySplit(ClientPtr client); +int nxagentWakeupBySplit(ClientPtr client); + +/* + * Wait until the given client is + * restarted. + */ + +void nxagentWaitWakeupBySplit(ClientPtr client); + +/* +FIXME: This must be moved to Drawable.h. +*/ +void nxagentWaitDrawable(DrawablePtr pDrawable); + +/* + * Wakeup all the sleeping clients. + */ + +void nxagentWakeupByReconnect(void); + +/* + * Reset the client state before + * closing it down. + */ + +void nxagentWakeupByReset(ClientPtr client); + +#endif /* __Client_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c new file mode 100644 index 000000000..d26d3524a --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.c @@ -0,0 +1,1677 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "X.h" +#include "Xproto.h" +#include "Xatom.h" +#include "selection.h" +#include "windowstr.h" +#include "scrnintstr.h" + +#include "Windows.h" +#include "Atoms.h" +#include "Agent.h" +#include "Args.h" +#include "Trap.h" +#include "Rootless.h" +#include "Clipboard.h" + +#include "gcstruct.h" +#include "xfixeswire.h" +#include "X11/include/Xfixes_nxagent.h" + +/* + * Use asyncronous get property replies. + */ + +#include "compext/Compext.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * These are defined in the dispatcher. + */ + +extern int NumCurrentSelections; +extern Selection *CurrentSelections; + +int nxagentLastClipboardClient = -1; + +static int agentClipboardStatus; +static int clientAccum; + +Atom serverCutProperty; +Atom clientCutProperty; +static Window serverWindow; + +static const int nxagentPrimarySelection = 0; +static const int nxagentClipboardSelection = 1; +static const int nxagentMaxSelections = 2; + +typedef struct _SelectionOwner +{ + Atom selection; + ClientPtr client; + Window window; + WindowPtr windowPtr; + Time lastTimeChanged; + +} SelectionOwner; + +static SelectionOwner *lastSelectionOwner; +static Atom nxagentLastRequestedSelection; +static Atom nxagentClipboardAtom; +static Atom nxagentTimestampAtom; + +/* + * Needed to handle the notify selection event to + * be sent to client once the selection property + * has been retrieved from the real X server. + */ + +typedef enum +{ + SelectionStageNone, + SelectionStageQuerySize, + SelectionStageWaitSize, + SelectionStageQueryData, + SelectionStageWaitData +} ClientSelectionStage; + +static WindowPtr lastClientWindowPtr; +static ClientPtr lastClientClientPtr; +static Window lastClientRequestor; +static Atom lastClientProperty; +static Atom lastClientSelection; +static Atom lastClientTarget; +static Time lastClientTime; +static Time lastClientReqTime; +static unsigned long lastClientPropertySize; + +static ClientSelectionStage lastClientStage; + +static Window lastServerRequestor; +static Atom lastServerProperty; +static Atom lastServerTarget; +static Time lastServerTime; + +static Atom serverTARGETS; +static Atom serverTEXT; +static Atom serverUTF8_STRING; +static Atom clientTARGETS; +static Atom clientTEXT; +static Atom clientCOMPOUND_TEXT; +static Atom clientUTF8_STRING; + +static char szAgentTARGETS[] = "TARGETS"; +static char szAgentTEXT[] = "TEXT"; +static char szAgentCOMPOUND_TEXT[] = "COMPOUND_TEXT"; +static char szAgentUTF8_STRING[] = "UTF8_STRING"; +static char szAgentNX_CUT_BUFFER_CLIENT[] = "NX_CUT_BUFFER_CLIENT"; + +/* + * Save the values queried from X server. + */ + +XFixesAgentInfoRec nxagentXFixesInfo = { -1, -1, -1, 0 }; + +extern Display *nxagentDisplay; + +Bool nxagentValidServerTargets(Atom target); +void nxagentSendSelectionNotify(Atom property); +void nxagentTransferSelection(int resource); +void nxagentCollectPropertyEvent(int resource); +void nxagentResetSelectionOwner(void); +WindowPtr nxagentGetClipboardWindow(Atom property, WindowPtr pWin); +void nxagentNotifyConvertFailure(ClientPtr client, Window requestor, + Atom selection, Atom target, Time time); +int nxagentSendNotify(xEvent *event); + +/* + * This is from NXproperty.c. + */ + +int GetWindowProperty(WindowPtr pWin, Atom property, long longOffset, long longLength, + Bool delete, Atom type, Atom *actualType, int *format, + unsigned long *nItems, unsigned long *bytesAfter, + unsigned char **propData); + +Bool nxagentValidServerTargets(Atom target) +{ + #ifdef DEBUG + fprintf(stderr, "nxagentValidServerTargets: Got called.\n"); + #endif + + if (target == XA_STRING) return True; + if (target == serverTEXT) return True; + /* by dimbor */ + if (target == serverUTF8_STRING) return True; + + return False; +} + +void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow) +{ + int i; + + #ifdef DEBUG + fprintf(stderr, "nxagentClearClipboard: Called with client [%p] window [%p].\n", + (void *) pClient, (void *) pWindow); + #endif + + /* + * Only for PRIMARY and CLIPBOARD selections. + */ + + for (i = 0; i < nxagentMaxSelections; i++) + { + if ((pClient != NULL && lastSelectionOwner[i].client == pClient) || + (pWindow != NULL && lastSelectionOwner[i].windowPtr == pWindow)) + { + #ifdef TEST + fprintf(stderr, "nxagentClearClipboard: Resetting state with client [%p] window [%p].\n", + (void *) pClient, (void *) pWindow); + #endif + + lastSelectionOwner[i].client = NULL; + lastSelectionOwner[i].window = None; + lastSelectionOwner[i].windowPtr = NULL; + lastSelectionOwner[i].lastTimeChanged = GetTimeInMillis(); + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + lastServerRequestor = None; + } + } + + if (pWindow == lastClientWindowPtr) + { + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + } + +} + +void nxagentClearSelection(XEvent *X) +{ + int i = 0; + + #ifdef DEBUG + fprintf(stderr, "nxagentClearSelection: Got called.\n"); + #endif + + if (agentClipboardStatus != 1 || + nxagentOption(Clipboard) == ClipboardServer) + { + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentClearSelection: SelectionClear event.\n"); + #endif + + while ((i < nxagentMaxSelections) && + (lastSelectionOwner[i].selection != X->xselectionclear.selection)) + { + i++; + } + + if (i < nxagentMaxSelections) + { + if (lastSelectionOwner[i].client != NULL) + { + xEvent x; + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = SelectionClear; + x.u.selectionClear.time = GetTimeInMillis(); + x.u.selectionClear.window = lastSelectionOwner[i].window; + x.u.selectionClear.atom = CurrentSelections[i].selection; + + (void) TryClientEvents(lastSelectionOwner[i].client, &x, 1, + NoEventMask, NoEventMask, + NullGrab); + } + + CurrentSelections[i].window = screenInfo.screens[0]->root->drawable.id; + CurrentSelections[i].client = NullClient; + + lastSelectionOwner[i].client = NULL; + lastSelectionOwner[i].window = None; + lastSelectionOwner[i].lastTimeChanged = GetTimeInMillis(); + } + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; +} + +void nxagentRequestSelection(XEvent *X) +{ + #ifdef DEBUG + int result; + #endif + int i = 0; + XSelectionEvent eventSelection; + + #ifdef DEBUG + fprintf(stderr, "nxagentRequestSelection: Got called.\n"); + #endif + + if (agentClipboardStatus != 1) + { + return; + } + + if (!nxagentValidServerTargets(X->xselectionrequest.target) || + (lastServerRequestor != None) || + ((X->xselectionrequest.selection != lastSelectionOwner[nxagentPrimarySelection].selection) && + (X->xselectionrequest.selection != lastSelectionOwner[nxagentClipboardSelection].selection))) + { +/* +FIXME: Do we need this? + + char *strTarget; + + strTarget = XGetAtomName(nxagentDisplay, X->xselectionrequest.target); + + fprintf(stderr, "SelectionRequest event aborting sele=[%s] target=[%s]\n", + validateString(NameForAtom(X->xselectionrequest.selection)), + validateString(NameForAtom(X->xselectionrequest.target))); + + fprintf(stderr, "SelectionRequest event aborting sele=[%s] ext target=[%s] Atom size is [%d]\n", + validateString(NameForAtom(X->xselectionrequest.selection)), strTarget, sizeof(Atom)); + + if (strTarget != NULL) + { + XFree(strTarget); + } +*/ + memset(&eventSelection, 0, sizeof(XSelectionEvent)); + eventSelection.property = None; + + if (X->xselectionrequest.target == serverTARGETS) + { + Atom xa_STRING = XA_STRING; + XChangeProperty (nxagentDisplay, + X->xselectionrequest.requestor, + X->xselectionrequest.property, + XInternAtom(nxagentDisplay, "ATOM", 0), + sizeof(Atom)*8, + PropModeReplace, + (unsigned char*)&xa_STRING, + 1); + eventSelection.property = X->xselectionrequest.property; + } + + if (X->xselectionrequest.target == nxagentTimestampAtom) + { + while ((i < NumCurrentSelections) && + lastSelectionOwner[i].selection != X->xselectionrequest.selection) i++; + + if (i < NumCurrentSelections) + { + XChangeProperty(nxagentDisplay, + X->xselectionrequest.requestor, + X->xselectionrequest.property, + X->xselectionrequest.target, + 32, + PropModeReplace, + (unsigned char *) &lastSelectionOwner[i].lastTimeChanged, + 1); + eventSelection.property = X->xselectionrequest.property; + } + } + + eventSelection.type = SelectionNotify; + eventSelection.send_event = True; + eventSelection.display = nxagentDisplay; + eventSelection.requestor = X->xselectionrequest.requestor; + eventSelection.selection = X->xselectionrequest.selection; + eventSelection.target = X->xselectionrequest.target; + eventSelection.time = X->xselectionrequest.time; + + #ifdef DEBUG + result = + #endif + XSendEvent(nxagentDisplay, + eventSelection.requestor, + False, + 0L, + (XEvent *) &eventSelection); + + #ifdef DEBUG + if (result == BadValue || result == BadWindow) + { + fprintf(stderr, "nxagentRequestSelection: WARNING! XSendEvent failed.\n"); + } + else + { + fprintf(stderr, "nxagentRequestSelection: XSendEvent sent to window [0x%lx].\n", + eventSelection.requestor); + } + #endif + + return; + } + + /* + * This is necessary in nxagentGetClipboardWindow. + */ + + nxagentLastRequestedSelection = X->xselectionrequest.selection; + + while ((i < nxagentMaxSelections) && + (lastSelectionOwner[i].selection != X->xselectionrequest.selection)) + { + i++; + } + + if (i < nxagentMaxSelections) + { + if ((lastClientWindowPtr != NULL) && (lastSelectionOwner[i].client != NULL)) + { + XConvertSelection(nxagentDisplay, CurrentSelections[i].selection, + X->xselectionrequest.target, serverCutProperty, + serverWindow, lastClientTime); + + #ifdef DEBUG + fprintf(stderr, "nxagentRequestSelection: Sent XConvertSelection.\n"); + #endif + } + else + { + if (lastSelectionOwner[i].client != NULL && + nxagentOption(Clipboard) != ClipboardClient) + { + xEvent x; + + lastServerProperty = X->xselectionrequest.property; + lastServerRequestor = X->xselectionrequest.requestor; + lastServerTarget = X->xselectionrequest.target; + + /* by dimbor */ + if (lastServerTarget != XA_STRING) + lastServerTarget = serverUTF8_STRING; + + lastServerTime = X->xselectionrequest.time; + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = SelectionRequest; + x.u.selectionRequest.time = GetTimeInMillis(); + x.u.selectionRequest.owner = lastSelectionOwner[i].window; + + /* + * Fictitious window. + */ + + x.u.selectionRequest.requestor = screenInfo.screens[0]->root->drawable.id; + + /* + * Don't send the same window, some programs are + * clever and verify cut and paste operations + * inside the same window and don't Notify at all. + * + * x.u.selectionRequest.requestor = lastSelectionOwnerWindow; + */ + + x.u.selectionRequest.selection = CurrentSelections[i].selection; + + /* by dimbor (idea from zahvatov) */ + if (X->xselectionrequest.target != XA_STRING) + x.u.selectionRequest.target = clientUTF8_STRING; + else + x.u.selectionRequest.target = XA_STRING; + + x.u.selectionRequest.property = clientCutProperty; + + (void) TryClientEvents(lastSelectionOwner[i].client, &x, 1, + NoEventMask, NoEventMask /* CantBeFiltered */, + NullGrab); + + #ifdef DEBUG + fprintf(stderr, "nxagentRequestSelection: Executed TryClientEvents with clientCutProperty.\n"); + #endif + } + else + { + /* + * Probably we must to send a Notify + * to requestor with property None. + */ + + eventSelection.type = SelectionNotify; + eventSelection.send_event = True; + eventSelection.display = nxagentDisplay; + eventSelection.requestor = X->xselectionrequest.requestor; + eventSelection.selection = X->xselectionrequest.selection; + eventSelection.target = X->xselectionrequest.target; + eventSelection.property = None; + eventSelection.time = X->xselectionrequest.time; + + #ifdef DEBUG + result = + #endif + XSendEvent(nxagentDisplay, + eventSelection.requestor, + False, + 0L, + (XEvent *) &eventSelection); + + #ifdef DEBUG + fprintf(stderr, "nxagentRequestSelection: Executed XSendEvent with property None.\n"); + #endif + } + } + } +} + +void nxagentSendSelectionNotify(Atom property) +{ + xEvent x; + + #ifdef DEBUG + fprintf (stderr, "nxagentSendSelectionNotify: Sending event to client [%d].\n", + lastClientClientPtr -> index); + #endif + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = SelectionNotify; + + x.u.selectionNotify.time = lastClientTime; + x.u.selectionNotify.requestor = lastClientRequestor; + x.u.selectionNotify.selection = lastClientSelection; + x.u.selectionNotify.target = lastClientTarget; + + x.u.selectionNotify.property = property; + + TryClientEvents(lastClientClientPtr, &x, 1, NoEventMask, + NoEventMask , NullGrab); + + return; +} + +void nxagentTransferSelection(int resource) +{ + int result; + + if (lastClientClientPtr -> index != resource) + { + #ifdef DEBUG + fprintf (stderr, "nxagentTransferSelection: WARNING! Inconsistent resource [%d] with current client [%d].\n", + resource, lastClientClientPtr -> index); + #endif + + nxagentSendSelectionNotify(None); + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + return; + } + + switch (lastClientStage) + { + case SelectionStageQuerySize: + { + /* + * Don't get data yet, just get size. We skip + * this stage in current implementation and + * go straight to the data. + */ + + nxagentLastClipboardClient = NXGetCollectPropertyResource(nxagentDisplay); + + if (nxagentLastClipboardClient == -1) + { + #ifdef WARNING + fprintf(stderr, "nxagentTransferSelection: WARNING! Asynchronous GetProperty queue full.\n"); + #endif + + result = -1; + } + else + { + result = NXCollectProperty(nxagentDisplay, + nxagentLastClipboardClient, + serverWindow, + serverCutProperty, + 0, + 0, + False, + AnyPropertyType); + } + + if (result == -1) + { + #ifdef DEBUG + fprintf (stderr, "nxagentTransferSelection: Aborting selection notify procedure for client [%d].\n", + lastClientClientPtr -> index); + #endif + + nxagentSendSelectionNotify(None); + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + return; + } + + #ifdef DEBUG + fprintf (stderr, "nxagentTransferSelection: Setting stage to [%d] for client [%d].\n", + SelectionStageWaitSize, lastClientClientPtr -> index); + #endif + + lastClientStage = SelectionStageWaitSize; + + break; + } + case SelectionStageQueryData: + { + /* + * Request the selection data now. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentTransferSelection: Getting property content from remote server.\n"); + #endif + + nxagentLastClipboardClient = NXGetCollectPropertyResource(nxagentDisplay); + + if (nxagentLastClipboardClient == -1) + { + #ifdef WARNING + fprintf(stderr, "nxagentTransferSelection: WARNING! Asynchronous GetProperty queue full.\n"); + #endif + + result = -1; + } + else + { + result = NXCollectProperty(nxagentDisplay, + nxagentLastClipboardClient, + serverWindow, + serverCutProperty, + 0, + lastClientPropertySize, + False, + AnyPropertyType); + } + + if (result == -1) + { + #ifdef DEBUG + fprintf (stderr, "nxagentTransferSelection: Aborting selection notify procedure for client [%d].\n", + lastClientClientPtr -> index); + #endif + + nxagentSendSelectionNotify(None); + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + return; + } + + #ifdef DEBUG + fprintf (stderr, "nxagentTransferSelection: Setting stage to [%d] for client [%d].\n", + SelectionStageWaitData, lastClientClientPtr -> index); + #endif + + lastClientStage = SelectionStageWaitData; + + break; + } + default: + { + #ifdef DEBUG + fprintf (stderr, "nxagentTransferSelection: WARNING! Inconsistent state [%d] for client [%d].\n", + lastClientStage, lastClientClientPtr -> index); + #endif + + break; + } + } +} + +void nxagentCollectPropertyEvent(int resource) +{ + Atom atomReturnType; + int resultFormat; + unsigned long ulReturnItems; + unsigned long ulReturnBytesLeft; + unsigned char *pszReturnData = NULL; + int result; + + /* + * We have received the notification so + * we can safely retrieve data from the + * client structure. + */ + + result = NXGetCollectedProperty(nxagentDisplay, + resource, + &atomReturnType, + &resultFormat, + &ulReturnItems, + &ulReturnBytesLeft, + &pszReturnData); + + nxagentLastClipboardClient = -1; + + if (result == 0) + { + #ifdef DEBUG + fprintf (stderr, "nxagentCollectPropertyEvent: Failed to get reply data for client [%d].\n", + lastClientClientPtr -> index); + #endif + + nxagentSendSelectionNotify(None); + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + if (pszReturnData != NULL) + { + XFree(pszReturnData); + } + + return; + } + + if (resultFormat != 8 && resultFormat != 16 && resultFormat != 32) + { + + #ifdef DEBUG + fprintf (stderr, "nxagentCollectPropertyEvent: WARNING! Invalid property " + "value.\n"); + #endif + + if (lastClientClientPtr != NULL) + { + nxagentSendSelectionNotify(None); + } + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + if (pszReturnData != NULL) + { + XFree(pszReturnData); + } + + return; + } + + switch (lastClientStage) + { + case SelectionStageWaitSize: + { + #ifdef DEBUG + fprintf (stderr, "nxagentCollectPropertyEvent: Got size notify event for client [%d].\n", + lastClientClientPtr -> index); + #endif + + if (ulReturnBytesLeft == 0) + { + #ifdef DEBUG + fprintf (stderr, "nxagentCollectPropertyEvent: Aborting selection notify procedure for client [%d].\n", + lastClientClientPtr -> index); + #endif + + nxagentSendSelectionNotify(None); + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + if (pszReturnData != NULL) + { + free(pszReturnData); + } + + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentCollectPropertyEvent: Got property size from remote server.\n"); + #endif + + /* + * Request the selection data now. + */ + + lastClientPropertySize = ulReturnBytesLeft; + lastClientStage = SelectionStageQueryData; + + nxagentTransferSelection(resource); + + break; + } + case SelectionStageWaitData: + { + #ifdef DEBUG + fprintf (stderr, "nxagentCollectPropertyEvent: Got data notify event for client [%d].\n", + lastClientClientPtr -> index); + #endif + + if (ulReturnBytesLeft != 0) + { + #ifdef DEBUG + fprintf (stderr, "nxagentCollectPropertyEvent: Aborting selection notify procedure for client [%d].\n", + lastClientClientPtr -> index); + #endif + + nxagentSendSelectionNotify(None); + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + if (pszReturnData != NULL) + { + free(pszReturnData); + } + + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentCollectPropertyEvent: Got property content from remote server.\n"); + #endif + + ChangeWindowProperty(lastClientWindowPtr, + lastClientProperty, + lastClientTarget, + resultFormat, PropModeReplace, + ulReturnItems, pszReturnData, 1); + + #ifdef DEBUG + fprintf(stderr, "nxagentCollectPropertyEvent: Selection property [%s] changed to [%s]\n", + validateString(NameForAtom(lastClientProperty)), pszReturnData); + #endif + + nxagentSendSelectionNotify(lastClientProperty); + + /* + * Enable further requests from clients. + */ + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + break; + } + default: + { + #ifdef DEBUG + fprintf (stderr, "nxagentCollectPropertyEvent: WARNING! Inconsistent state [%d] for client [%d].\n", + lastClientStage, lastClientClientPtr -> index); + #endif + + break; + } + } + + XFree(pszReturnData); + pszReturnData = NULL; +} + +void nxagentNotifySelection(XEvent *X) +{ + int result; + + XSelectionEvent eventSelection; + + #ifdef DEBUG + fprintf(stderr, "nxagentNotifySelection: Got called.\n"); + #endif + + if (agentClipboardStatus != 1) + { + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentNotifySelection: SelectionNotify event.\n"); + #endif + + if (lastClientWindowPtr != NULL) + { + if ((lastClientStage == SelectionStageNone) && (X->xselection.property == serverCutProperty)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentNotifySelection: Starting selection transferral for client [%d].\n", + lastClientClientPtr -> index); + #endif + + /* + * The state machine is able to work in two phases. In the first + * phase we get the size of property data, in the second we get + * the actual data. We save a round-trip by requesting a prede- + * termined amount of data in a single GetProperty and by discar- + * ding the remaining part. This is not the optimal solution (we + * could get the remaining part if it doesn't fit in a single + * reply) but, at least with text, it should work in most situa- + * tions. + */ + + lastClientStage = SelectionStageQueryData; + lastClientPropertySize = 262144; + + nxagentTransferSelection(lastClientClientPtr -> index); + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentNotifySelection: WARNING! Resetting selection transferral for client [%d].\n", + lastClientClientPtr -> index); + #endif + + nxagentSendSelectionNotify(None); + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + } + + return; + } + else + { + int i = 0; + + while ((i < nxagentMaxSelections) && (lastSelectionOwner[i].selection != X->xselection.selection)) + { + i++; + } + + if (i < nxagentMaxSelections) + { + if ((lastSelectionOwner[i].client != NULL) && + (lastSelectionOwner[i].windowPtr != NULL) && + (X->xselection.property == clientCutProperty)) + { + Atom atomReturnType; + int resultFormat; + unsigned long ulReturnItems; + unsigned long ulReturnBytesLeft; + unsigned char *pszReturnData = NULL; + + result = GetWindowProperty(lastSelectionOwner[i].windowPtr, clientCutProperty, 0, 0, False, + AnyPropertyType, &atomReturnType, &resultFormat, + &ulReturnItems, &ulReturnBytesLeft, &pszReturnData); + + if (result == BadAlloc || result == BadAtom || + result == BadMatch || result == BadValue || + result == BadWindow) + { + fprintf (stderr, "Client GetProperty failed error ="); + lastServerProperty = None; + switch (result) + { + case BadAtom: + fprintf (stderr, "BadAtom\n"); + break; + case BadValue: + fprintf (stderr, "BadValue\n"); + break; + case BadWindow: + fprintf (stderr, "BadWindow\n"); + break; + } + } + else + { + result = GetWindowProperty(lastSelectionOwner[i].windowPtr, clientCutProperty, 0, + ulReturnBytesLeft, False, AnyPropertyType, &atomReturnType, + &resultFormat, &ulReturnItems, &ulReturnBytesLeft, + &pszReturnData); + + if (result == BadAlloc || result == BadAtom || + result == BadMatch || result == BadValue || + result == BadWindow) + { + fprintf (stderr, "SelectionNotify - XChangeProperty failed\n"); + + lastServerProperty = None; + } + else + { + result = XChangeProperty(nxagentDisplay, + lastServerRequestor, + lastServerProperty, + lastServerTarget, + 8, + PropModeReplace, + pszReturnData, + ulReturnItems); + } + + /* + * if (pszReturnData) + * { + * free(pszReturnData); + * pszReturnData=NULL; + * } + */ + + } + + memset(&eventSelection, 0, sizeof(XSelectionEvent)); + eventSelection.type = SelectionNotify; + eventSelection.send_event = True; + eventSelection.display = nxagentDisplay; + eventSelection.requestor = lastServerRequestor; + + eventSelection.selection = X->xselection.selection; + + /* + * eventSelection.target = X->xselection.target; + */ + + eventSelection.target = lastServerTarget; + eventSelection.property = lastServerProperty; + eventSelection.time = lastServerTime; + + /* + * eventSelection.time = CurrentTime; + * eventSelection.time = lastServerTime; + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentNotifySelection: Sending event to requestor.\n"); + #endif + + result = XSendEvent(nxagentDisplay, + eventSelection.requestor, + False, + 0L, + (XEvent *) &eventSelection); + + if (result == BadValue || result == BadWindow) + { + fprintf (stderr, "SelectionRequest - XSendEvent failed\n"); + } + + lastServerRequestor = None; /* allow further request */ + } + } + } +} + +/* + * Acquire selection so we don't get selection + * requests from real X clients. + */ + +void nxagentResetSelectionOwner() +{ + int i; + + if (lastServerRequestor != None) + { + #ifdef TEST + fprintf (stderr, "nxagentResetSelectionOwner: WARNING! Requestor window [0x%lx] already found.\n", + lastServerRequestor); + #endif + + return; + } + + /* + * Only for PRIMARY and CLIPBOARD selections. + */ + + for (i = 0; i < nxagentMaxSelections; i++) + { + XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, serverWindow, CurrentTime); + + fprintf (stderr, "nxagentResetSelectionOwner: Reset clipboard state.\n"); + + lastSelectionOwner[i].client = NULL; + lastSelectionOwner[i].window = None; + lastSelectionOwner[i].windowPtr = NULL; + lastSelectionOwner[i].lastTimeChanged = GetTimeInMillis(); + } + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + lastServerRequestor = None; + + return; +} + +void nxagentSetSelectionOwner(Selection *pSelection) +{ + int i; + #ifdef DEBUG + fprintf(stderr, "nxagentSetSelectionOwner: Got called.\n"); + #endif + + if (agentClipboardStatus != 1) + { + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentSetSelectionOwner: Setting selection owner to window [0x%lx].\n", + serverWindow); + #endif + + #ifdef TEST + if (lastServerRequestor != None) + { + fprintf (stderr, "nxagentSetSelectionOwner: WARNING! Requestor window [0x%lx] already found.\n", + lastServerRequestor); + } + #endif + + /* + * Only for PRIMARY and CLIPBOARD selections. + */ + + for (i = 0; i < nxagentMaxSelections; i++) + { + if (pSelection->selection == CurrentSelections[i].selection) + { + XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, serverWindow, CurrentTime); + + lastSelectionOwner[i].client = pSelection->client; + lastSelectionOwner[i].window = pSelection->window; + lastSelectionOwner[i].windowPtr = pSelection->pWin; + lastSelectionOwner[i].lastTimeChanged = GetTimeInMillis(); + } + } + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + lastServerRequestor = None; + +/* +FIXME + + if (XGetSelectionOwner(nxagentDisplay,pSelection->selection)==serverWindow) + { + fprintf (stderr, "NXdispatch: SetSelectionOwner OK\n"); + + lastSelectionOwnerSelection = pSelection; + lastSelectionOwnerClient = pSelection->client; + lastSelectionOwnerWindow = pSelection->window; + lastSelectionOwnerWindowPtr = pSelection->pWin; + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + + lastServerRequestor = None; + } + else fprintf (stderr, "nxagentSetSelectionOwner: SetSelectionOwner failed\n"); +*/ +} + +void nxagentNotifyConvertFailure(ClientPtr client, Window requestor, + Atom selection, Atom target, Time time) +{ + xEvent x; + +/* +FIXME: Why this pointer can be not a valid + client pointer? +*/ + if (clients[client -> index] != client) + { + #ifdef WARNING + fprintf(stderr, "nxagentNotifyConvertFailure: WARNING! Invalid client pointer."); + #endif + + return; + } + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = SelectionNotify; + x.u.selectionNotify.time = time; + x.u.selectionNotify.requestor = requestor; + x.u.selectionNotify.selection = selection; + x.u.selectionNotify.target = target; + x.u.selectionNotify.property = None; + + (void) TryClientEvents(client, &x, 1, NoEventMask, + NoEventMask , NullGrab); +} + +int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, + Window requestor, Atom property, Atom target, Time time) +{ + const char *strTarget; + int i; + + if (agentClipboardStatus != 1 || + nxagentOption(Clipboard) == ClipboardServer) + { + return 0; + } + + /* + * There is a client owner on the agent side, let normal stuff happen. + */ + + /* + * Only for PRIMARY and CLIPBOARD selections. + */ + + for (i = 0; i < nxagentMaxSelections; i++) + { + if ((selection == CurrentSelections[i].selection) && + (lastSelectionOwner[i].client != NULL)) + { + return 0; + } + } + + if (lastClientWindowPtr != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentConvertSelection: lastClientWindowPtr != NULL.\n"); + #endif + + if ((GetTimeInMillis() - lastClientReqTime) > 5000) + { + #ifdef DEBUG + fprintf(stderr, "nxagentConvertSelection: timeout expired on last request, " + "notifying failure to client\n"); + #endif + + nxagentNotifyConvertFailure(lastClientClientPtr, lastClientRequestor, + lastClientSelection, lastClientTarget, lastClientTime); + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentConvertSelection: got request " + "before timeout expired on last request, notifying failure to client\n"); + #endif + + nxagentNotifyConvertFailure(client, requestor, selection, target, time); + + return 1; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentConvertSelection: client [%d] ask for sel [%s] " + "on window [%lx] prop [%s] target [%s].\n", + client -> index, validateString(NameForAtom(selection)), requestor, + validateString(NameForAtom(property)), validateString(NameForAtom(target))); + #endif + + strTarget = NameForAtom(target); + + if (strTarget == NULL) + { + return 1; + } + + if (target == clientTARGETS) + { + Atom xa_STRING[4]; + xEvent x; + + /* --- Order changed by dimbor (prevent sending COMPOUND_TEXT to client --- */ + xa_STRING[0] = XA_STRING; + xa_STRING[1] = clientUTF8_STRING; + xa_STRING[2] = clientTEXT; + xa_STRING[3] = clientCOMPOUND_TEXT; + + ChangeWindowProperty(pWin, + property, + MakeAtom("ATOM", 4, 1), + sizeof(Atom)*8, + PropModeReplace, + 4, + &xa_STRING, 1); + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = SelectionNotify; + x.u.selectionNotify.time = time; + x.u.selectionNotify.requestor = requestor; + x.u.selectionNotify.selection = selection; + x.u.selectionNotify.target = target; + x.u.selectionNotify.property = property; + + (void) TryClientEvents(client, &x, 1, NoEventMask, + NoEventMask , NullGrab); + + return 1; + } + + if (target == MakeAtom("TIMESTAMP", 9, 1)) + { + xEvent x; + int i = 0; + + while ((i < NumCurrentSelections) && + CurrentSelections[i].selection != selection) i++; + + if (i < NumCurrentSelections) + { + ChangeWindowProperty(pWin, + property, + target, + 32, + PropModeReplace, + 1, + (unsigned char *) &lastSelectionOwner[i].lastTimeChanged, + 1); + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = SelectionNotify; + x.u.selectionNotify.time = time; + x.u.selectionNotify.requestor = requestor; + x.u.selectionNotify.selection = selection; + x.u.selectionNotify.target = target; + x.u.selectionNotify.property = property; + + (void) TryClientEvents(client, &x, 1, NoEventMask, + NoEventMask , NullGrab); + + return 1; + + } + } + + if (lastClientClientPtr == client && (GetTimeInMillis() - lastClientReqTime < 5000)) + { + /* + * The same client made consecutive requests + * of clipboard contents with less than 5 + * seconds time interval between them. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentConvertSelection: Consecutives request from client [%p] selection [%ld] " + "elapsed time [%lu] clientAccum [%d]\n", (void *) client, selection, + GetTimeInMillis() - lastClientReqTime, clientAccum); + #endif + + clientAccum++; + } + else + { + if (lastClientClientPtr != client) + { + clientAccum = 0; + } + } + + if ((target == clientTEXT) || + (target == XA_STRING) || + (target == clientCOMPOUND_TEXT) || + (target == clientUTF8_STRING)) + { + lastClientWindowPtr = pWin; + lastClientStage = SelectionStageNone; + lastClientRequestor = requestor; + lastClientClientPtr = client; + lastClientTime = time; + lastClientProperty = property; + lastClientSelection = selection; + lastClientTarget = target; + + lastClientReqTime = (GetTimeInMillis() - lastClientReqTime) > 5000 ? + GetTimeInMillis() : lastClientReqTime; + + if (selection == MakeAtom("CLIPBOARD", 9, 0)) + { + selection = lastSelectionOwner[nxagentClipboardSelection].selection; + } + + if (target == clientUTF8_STRING) + { + XConvertSelection(nxagentDisplay, selection, serverUTF8_STRING, serverCutProperty, + serverWindow, CurrentTime); + } + else + { + XConvertSelection(nxagentDisplay, selection, XA_STRING, serverCutProperty, + serverWindow, CurrentTime); + } + + #ifdef DEBUG + fprintf(stderr, "nxagentConvertSelection: Sent XConvertSelection with target=[%s], property [%s]\n", + validateString(NameForAtom(target)), validateString(NameForAtom(property))); + #endif + + return 1; + } + else + { + xEvent x; + + #ifdef DEBUG + fprintf(stderr, "nxagentConvertSelection: Xserver generates a SelectionNotify event " + "to the requestor with property None.\n"); + #endif + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = SelectionNotify; + x.u.selectionNotify.time = time; + x.u.selectionNotify.requestor = requestor; + x.u.selectionNotify.selection = selection; + x.u.selectionNotify.target = target; + x.u.selectionNotify.property = None; + (void) TryClientEvents(client, &x, 1, NoEventMask, NoEventMask , NullGrab); + return 1; + } + return 0; +} + +int nxagentSendNotify(xEvent *event) +{ + #ifdef DEBUG + fprintf(stderr, "nxagentSendNotify: Got called.\n"); + #endif + + if (agentClipboardStatus != 1) + { + return 0; + } + + if (event->u.selectionNotify.property == clientCutProperty) + { + XSelectionEvent x; + int result; + + /* + * Setup selection notify event to real server. + */ + + memset(&x, 0, sizeof(XSelectionEvent)); + x.type = SelectionNotify; + x.send_event = True; + x.display = nxagentDisplay; + x.requestor = serverWindow; + + /* + * On real server, the right CLIPBOARD atom is + * XInternAtom(nxagentDisplay, "CLIPBOARD", 1). + */ + + if (event->u.selectionNotify.selection == MakeAtom("CLIPBOARD", 9, 0)) + { + x.selection = lastSelectionOwner[nxagentClipboardSelection].selection; + } + else + { + x.selection = event->u.selectionNotify.selection; + } + + x.target = event->u.selectionNotify.target; + x.property = event->u.selectionNotify.property; + x.time = CurrentTime; + + #ifdef DEBUG + fprintf(stderr, "nxagentSendNotify: Propagating clientCutProperty.\n"); + #endif + + result = XSendEvent (nxagentDisplay, x.requestor, False, + 0L, (XEvent *) &x); + + if (result == BadValue || result == BadWindow) + { + fprintf (stderr, "nxagentSendNotify: XSendEvent failed.\n"); + } + + return 1; + } + + return 0; +} + +WindowPtr nxagentGetClipboardWindow(Atom property, WindowPtr pWin) +{ + int i = 0; + + #ifdef DEBUG + fprintf(stderr, "nxagentGetClipboardWindow: Got called.\n"); + #endif + + while ((i < nxagentMaxSelections) && + (lastSelectionOwner[i].selection != nxagentLastRequestedSelection)) + { + i++; + } + + if ((i < nxagentMaxSelections) && (property == clientCutProperty) && + (lastSelectionOwner[i].windowPtr != NULL)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentGetClipboardWindow: Returning last clipboard owner window.\n"); + #endif + + return lastSelectionOwner[i].windowPtr; + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentGetClipboardWindow: Returning original target window.\n"); + #endif + + return pWin; + } + +} + +int nxagentInitClipboard(WindowPtr pWin) +{ + int i; + Window iWindow = nxagentWindow(pWin); + + #ifdef DEBUG + fprintf(stderr, "nxagentInitClipboard: Got called.\n"); + #endif + + if (lastSelectionOwner != NULL) + { + free(lastSelectionOwner); + lastSelectionOwner = NULL; + } + + lastSelectionOwner = (SelectionOwner *) malloc(2 * sizeof(SelectionOwner)); + + if (lastSelectionOwner == NULL) + { + FatalError("nxagentInitClipboard: Failed to allocate memory for the clipboard selections.\n"); + } + + nxagentClipboardAtom = nxagentAtoms[10]; /* CLIPBOARD */ + nxagentTimestampAtom = nxagentAtoms[11]; /* TIMESTAMP */ + + lastSelectionOwner[nxagentPrimarySelection].selection = XA_PRIMARY; + lastSelectionOwner[nxagentPrimarySelection].client = NullClient; + lastSelectionOwner[nxagentPrimarySelection].window = screenInfo.screens[0]->root->drawable.id; + lastSelectionOwner[nxagentPrimarySelection].windowPtr = NULL; + lastSelectionOwner[nxagentPrimarySelection].lastTimeChanged = GetTimeInMillis(); + + lastSelectionOwner[nxagentClipboardSelection].selection = nxagentClipboardAtom; + lastSelectionOwner[nxagentClipboardSelection].client = NullClient; + lastSelectionOwner[nxagentClipboardSelection].window = screenInfo.screens[0]->root->drawable.id; + lastSelectionOwner[nxagentClipboardSelection].windowPtr = NULL; + lastSelectionOwner[nxagentClipboardSelection].lastTimeChanged = GetTimeInMillis(); + + #ifdef NXAGENT_TIMESTAMP + { + extern unsigned long startTime; + + fprintf(stderr, "nxagentInitClipboard: Initializing start [%d] milliseconds.\n", + GetTimeInMillis() - startTime); + } + #endif + + agentClipboardStatus = 0; + serverWindow = iWindow; + + /* + * Local property to hold pasted data. + */ + + serverCutProperty = nxagentAtoms[5]; /* NX_CUT_BUFFER_SERVER */ + serverTARGETS = nxagentAtoms[6]; /* TARGETS */ + serverTEXT = nxagentAtoms[7]; /* TEXT */ + serverUTF8_STRING = nxagentAtoms[12]; /* UTF8_STRING */ + + if (serverCutProperty == None) + { + #ifdef PANIC + fprintf(stderr, "nxagentInitClipboard: PANIC! Could not create NX_CUT_BUFFER_SERVER atom\n"); + #endif + + return -1; + } + + #ifdef TEST + fprintf(stderr, "nxagentInitClipboard: Setting owner of selection [%s][%d] on window 0x%lx\n", + "NX_CUT_BUFFER_SERVER", (int) serverCutProperty, iWindow); + #endif + + XSetSelectionOwner(nxagentDisplay, serverCutProperty, iWindow, CurrentTime); + + if (XQueryExtension(nxagentDisplay, + "XFIXES", + &nxagentXFixesInfo.Opcode, + &nxagentXFixesInfo.EventBase, + &nxagentXFixesInfo.ErrorBase) == 0) + { + ErrorF("Unable to initialize XFixes extension.\n"); + } + + else + { + #ifdef TEST + fprintf(stderr, "nxagentInitClipboard: Registering for XFixesSelectionNotify events.\n"); + #endif + + for (i = 0; i < nxagentMaxSelections; i++) + { + XFixesSelectSelectionInput(nxagentDisplay, iWindow, + lastSelectionOwner[i].selection, + XFixesSetSelectionOwnerNotifyMask | + XFixesSelectionWindowDestroyNotifyMask | + XFixesSelectionClientCloseNotifyMask); + } + + nxagentXFixesInfo.Initialized = 1; + } + + /* + The first paste from CLIPBOARD did not work directly after + session start. Removing this code makes it work. It is unsure why + it was introduced in the first place so it is possible that we + see other effects by leaving out this code. + + Fixes X2Go bug #952, see https://bugs.x2go.org/952 for details . + + if (nxagentSessionId[0]) + { + #ifdef TEST + fprintf(stderr, "nxagentInitClipboard: setting the ownership of %s to %lx" + " and registering for PropertyChangeMask events\n", + validateString(XGetAtomName(nxagentDisplay, nxagentAtoms[10])), iWindow); + #endif + + XSetSelectionOwner(nxagentDisplay, nxagentAtoms[10], iWindow, CurrentTime); + pWin -> eventMask |= PropertyChangeMask; + nxagentChangeWindowAttributes(pWin, CWEventMask); + } + */ + + if (nxagentReconnectTrap) + { + /* + * Only for PRIMARY and CLIPBOARD selections. + */ + + for (i = 0; i < nxagentMaxSelections; i++) + { + if (lastSelectionOwner[i].client && lastSelectionOwner[i].window) + { + XSetSelectionOwner(nxagentDisplay, lastSelectionOwner[i].selection, iWindow, CurrentTime); + } + } + } + else + { + lastSelectionOwner[nxagentPrimarySelection].client = NULL; + lastSelectionOwner[nxagentClipboardSelection].client = NULL; + + lastServerRequestor = None; + + lastClientWindowPtr = NULL; + lastClientStage = SelectionStageNone; + lastClientReqTime = GetTimeInMillis(); + + clientCutProperty = MakeAtom(szAgentNX_CUT_BUFFER_CLIENT, + strlen(szAgentNX_CUT_BUFFER_CLIENT), 1); + clientTARGETS = MakeAtom(szAgentTARGETS, strlen(szAgentTARGETS), True); + clientTEXT = MakeAtom(szAgentTEXT, strlen(szAgentTEXT), True); + clientCOMPOUND_TEXT = MakeAtom(szAgentCOMPOUND_TEXT, strlen(szAgentCOMPOUND_TEXT), True); + clientUTF8_STRING = MakeAtom(szAgentUTF8_STRING, strlen(szAgentUTF8_STRING), True); + + if (clientCutProperty == None) + { + #ifdef PANIC + fprintf(stderr, "nxagentInitClipboard: PANIC! " + "Could not create NX_CUT_BUFFER_CLIENT atom.\n"); + #endif + + return -1; + } + } + + agentClipboardStatus = 1; + + #ifdef DEBUG + fprintf(stderr, "nxagentInitClipboard: Clipboard initialization completed.\n"); + #endif + + #ifdef NXAGENT_TIMESTAMP + { + extern unsigned long startTime; + + fprintf(stderr, "nxagentInitClipboard: initializing ends [%d] milliseconds.\n", + GetTimeInMillis() - startTime); + } + #endif + + return 1; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Clipboard.h b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.h new file mode 100644 index 000000000..62fc32fd9 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Clipboard.h @@ -0,0 +1,69 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Clipboard_H__ +#define __Clipboard_H__ + +/* + * Queried at clipboard initialization. + */ + +typedef struct _XFixesAgentInfo +{ + int Opcode; + int EventBase; + int ErrorBase; + int Initialized; + +} XFixesAgentInfoRec; + +extern XFixesAgentInfoRec nxagentXFixesInfo; + +/* + * Create the NX_CUT_BUFFER_CLIENT atom and + * initialize the required property to exchange + * data with the X server. + */ + +extern int nxagentInitClipboard(WindowPtr pWindow); + +/* + * Called whenever a client or a window is + * destroyed to let the clipboard code to + * release any pointer to the referenced + * structures. + */ + +extern void nxagentClearClipboard(ClientPtr pClient, WindowPtr pWindow); + +extern void nxagentSetSelectionOwner(Selection *pSelection); +extern int nxagentConvertSelection(ClientPtr client, WindowPtr pWin, Atom selection, + Window requestor, Atom property, Atom target, Time time); + +void nxagentClearSelection(); +void nxagentRequestSelection(); +void nxagentNotifySelection(); + +#endif /* __Clipboard_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Colormap.c b/nx-X11/programs/Xserver/hw/nxagent/Colormap.c new file mode 100644 index 000000000..c21bcbbe7 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Colormap.c @@ -0,0 +1,600 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include "X.h" +#include "Xproto.h" +#include "scrnintstr.h" +#include "../../include/window.h" +#include "windowstr.h" +#include "colormapst.h" +#include "resource.h" + +#include "Agent.h" + + +#include "Display.h" +#include "Screen.h" +#include "Colormap.h" +#include "Visual.h" +#include "Windows.h" +#include "Args.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +static ColormapPtr InstalledMaps[MAXSCREENS]; + +static Bool nxagentInstalledDefaultColormap = False; + +Bool nxagentReconnectAllColormap(void *p0); + +Bool nxagentCreateColormap(ColormapPtr pCmap) +{ + VisualPtr pVisual; + XColor *colors; + int i, ncolors; + Pixel red, green, blue; + Pixel redInc, greenInc, blueInc; + + Visual *visual; + int class; + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "nxagentCreateColormap: Going to create new colormap with " + " visual [%lu].\n", pCmap->pVisual); + #endif + + pVisual = pCmap->pVisual; + ncolors = pVisual->ColormapEntries; + + pCmap->devPriv = (void *)malloc(sizeof(nxagentPrivColormap)); + + if (((visual = nxagentVisual(pVisual))) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentCreateColormap: WARNING: Visual not found. Using default visual.\n"); + #endif + + visual = nxagentVisuals[nxagentDefaultVisualIndex].visual; + class = nxagentVisuals[nxagentDefaultVisualIndex].class; + } + else + { + class = pVisual->class; + } + + + nxagentColormapPriv(pCmap)->colormap = + XCreateColormap(nxagentDisplay, + nxagentDefaultWindows[pCmap->pScreen->myNum], + visual, + (class & DynamicClass) ? + AllocAll : AllocNone); + + switch (class) { + case StaticGray: /* read only */ + colors = (XColor *)malloc(ncolors * sizeof(XColor)); + for (i = 0; i < ncolors; i++) + colors[i].pixel = i; + XQueryColors(nxagentDisplay, nxagentColormap(pCmap), colors, ncolors); + for (i = 0; i < ncolors; i++) { + pCmap->red[i].co.local.red = colors[i].red; + pCmap->red[i].co.local.green = colors[i].red; + pCmap->red[i].co.local.blue = colors[i].red; + } + free(colors); + break; + + case StaticColor: /* read only */ + colors = (XColor *)malloc(ncolors * sizeof(XColor)); + for (i = 0; i < ncolors; i++) + colors[i].pixel = i; + XQueryColors(nxagentDisplay, nxagentColormap(pCmap), colors, ncolors); + for (i = 0; i < ncolors; i++) { + pCmap->red[i].co.local.red = colors[i].red; + pCmap->red[i].co.local.green = colors[i].green; + pCmap->red[i].co.local.blue = colors[i].blue; + } + free(colors); + break; + + case TrueColor: /* read only */ + colors = (XColor *)malloc(ncolors * sizeof(XColor)); + red = green = blue = 0L; + redInc = lowbit(pVisual->redMask); + greenInc = lowbit(pVisual->greenMask); + blueInc = lowbit(pVisual->blueMask); + for (i = 0; i < ncolors; i++) { + colors[i].pixel = red | green | blue; + red += redInc; + if (red > pVisual->redMask) red = 0L; + green += greenInc; + if (green > pVisual->greenMask) green = 0L; + blue += blueInc; + if (blue > pVisual->blueMask) blue = 0L; + } + XQueryColors(nxagentDisplay, nxagentColormap(pCmap), colors, ncolors); + for (i = 0; i < ncolors; i++) { + pCmap->red[i].co.local.red = colors[i].red; + pCmap->green[i].co.local.green = colors[i].green; + pCmap->blue[i].co.local.blue = colors[i].blue; + } + free(colors); + break; + + case GrayScale: /* read and write */ + break; + + case PseudoColor: /* read and write */ + break; + + case DirectColor: /* read and write */ + break; + } + + return True; +} + +void nxagentDestroyColormap(ColormapPtr pCmap) +{ + XFreeColormap(nxagentDisplay, nxagentColormap(pCmap)); + free(pCmap->devPriv); +} + +#define SEARCH_PREDICATE \ + (nxagentWindow(pWin) != None && wColormap(pWin) == icws->cmapIDs[i]) + +static int nxagentCountInstalledColormapWindows(WindowPtr pWin, void * ptr) +{ + nxagentInstalledColormapWindows *icws = (nxagentInstalledColormapWindows *) ptr; + + int i; + + for (i = 0; i < icws->numCmapIDs; i++) + if (SEARCH_PREDICATE) { + icws->numWindows++; + return WT_DONTWALKCHILDREN; + } + + return WT_WALKCHILDREN; +} + +static int nxagentGetInstalledColormapWindows(WindowPtr pWin, void * ptr) +{ + nxagentInstalledColormapWindows *icws = (nxagentInstalledColormapWindows *)ptr; + int i; + + for (i = 0; i < icws->numCmapIDs; i++) + if (SEARCH_PREDICATE) { + icws->windows[icws->index++] = nxagentWindow(pWin); + return WT_DONTWALKCHILDREN; + } + + return WT_WALKCHILDREN; +} + +static Window *nxagentOldInstalledColormapWindows = NULL; +static int nxagentNumOldInstalledColormapWindows = 0; + +static Bool nxagentSameInstalledColormapWindows(Window *windows, int numWindows) +{ + if (nxagentNumOldInstalledColormapWindows != numWindows) + return False; + + if (nxagentOldInstalledColormapWindows == windows) + return True; + + if (nxagentOldInstalledColormapWindows == NULL || windows == NULL) + return False; + + if (memcmp(nxagentOldInstalledColormapWindows, windows, + numWindows * sizeof(Window))) + return False; + + return True; +} + +void nxagentSetInstalledColormapWindows(ScreenPtr pScreen) +{ + nxagentInstalledColormapWindows icws; + int numWindows; + + icws.cmapIDs = (Colormap *)malloc(pScreen->maxInstalledCmaps * + sizeof(Colormap)); + icws.numCmapIDs = nxagentListInstalledColormaps(pScreen, icws.cmapIDs); + icws.numWindows = 0; + WalkTree(pScreen, nxagentCountInstalledColormapWindows, (void *)&icws); + if (icws.numWindows) { + icws.windows = (Window *)malloc((icws.numWindows + 1) * sizeof(Window)); + icws.index = 0; + WalkTree(pScreen, nxagentGetInstalledColormapWindows, (void *)&icws); + icws.windows[icws.numWindows] = nxagentDefaultWindows[pScreen->myNum]; + numWindows = icws.numWindows + 1; + } + else { + icws.windows = NULL; + numWindows = 0; + } + + free(icws.cmapIDs); + + if (!nxagentSameInstalledColormapWindows(icws.windows, icws.numWindows)) { + if (nxagentOldInstalledColormapWindows) + free(nxagentOldInstalledColormapWindows); + +#ifdef _XSERVER64 + { + int i; + Window64 *windows = (Window64 *)malloc(numWindows * sizeof(Window64)); + + for(i = 0; i < numWindows; ++i) + windows[i] = icws.windows[i]; + XSetWMColormapWindows(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], + windows, numWindows); + free(windows); + } +#else + XSetWMColormapWindows(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], + icws.windows, numWindows); +#endif + + nxagentOldInstalledColormapWindows = icws.windows; + nxagentNumOldInstalledColormapWindows = icws.numWindows; + +#ifdef DUMB_WINDOW_MANAGERS + /* + This code is for dumb window managers. + This will only work with default local visual colormaps. + */ + if (icws.numWindows) + { + WindowPtr pWin; + Visual *visual; + ColormapPtr pCmap; + + pWin = nxagentWindowPtr(icws.windows[0]); + visual = nxagentVisualFromID(pScreen, wVisual(pWin)); + + if (visual == nxagentDefaultVisual(pScreen)) + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), + RT_COLORMAP); + else + pCmap = (ColormapPtr)LookupIDByType(pScreen->defColormap, + RT_COLORMAP); + + if (pCmap != NULL) + { + XSetWindowColormap(nxagentDisplay, + nxagentDefaultWindows[pScreen->myNum], + nxagentColormap(pCmap)); + } + #ifdef WARNING + else + { + fprintf(stderr, "nxagentSetInstalledColormapWindows: WARNING! " + "Window at [%p] has no colormap with class [%d].\n", + (void *)pWin, pWin -> drawable.class); + } + #endif + } +#endif /* DUMB_WINDOW_MANAGERS */ + } + else + if (icws.windows) free(icws.windows); +} + +void nxagentSetScreenSaverColormapWindow(ScreenPtr pScreen) +{ + if (nxagentOldInstalledColormapWindows) + free(nxagentOldInstalledColormapWindows); + +#ifdef _XSERVER64 + { + Window64 window; + + window = nxagentScreenSaverWindows[pScreen->myNum]; + XSetWMColormapWindows(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], + &window, 1); + nxagentScreenSaverWindows[pScreen->myNum] = window; + } +#else + XSetWMColormapWindows(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], + &nxagentScreenSaverWindows[pScreen->myNum], 1); +#endif /* _XSERVER64 */ + + nxagentOldInstalledColormapWindows = NULL; + nxagentNumOldInstalledColormapWindows = 0; + + nxagentDirectUninstallColormaps(pScreen); +} + +void nxagentDirectInstallColormaps(ScreenPtr pScreen) +{ + int i, n; + Colormap pCmapIDs[MAXCMAPS]; + + if (!nxagentDoDirectColormaps) return; + + n = (*pScreen->ListInstalledColormaps)(pScreen, pCmapIDs); + + for (i = 0; i < n; i++) { + ColormapPtr pCmap; + + pCmap = (ColormapPtr)LookupIDByType(pCmapIDs[i], RT_COLORMAP); + if (pCmap) + XInstallColormap(nxagentDisplay, nxagentColormap(pCmap)); + } +} + +void nxagentDirectUninstallColormaps(ScreenPtr pScreen) +{ + int i, n; + Colormap pCmapIDs[MAXCMAPS]; + + if (!nxagentDoDirectColormaps) return; + + n = (*pScreen->ListInstalledColormaps)(pScreen, pCmapIDs); + + for (i = 0; i < n; i++) { + ColormapPtr pCmap; + + pCmap = (ColormapPtr)LookupIDByType(pCmapIDs[i], RT_COLORMAP); + if (pCmap) + XUninstallColormap(nxagentDisplay, nxagentColormap(pCmap)); + } +} + +void nxagentInstallColormap(ColormapPtr pCmap) +{ + int index; + ColormapPtr pOldCmap; + + index = pCmap->pScreen->myNum; + pOldCmap = InstalledMaps[index]; + + if(pCmap != pOldCmap) + { + nxagentDirectUninstallColormaps(pCmap->pScreen); + + /* Uninstall pInstalledMap. Notify all interested parties. */ + if(pOldCmap != (ColormapPtr)None) + WalkTree(pCmap->pScreen, TellLostMap, (void *)&pOldCmap->mid); + + InstalledMaps[index] = pCmap; + WalkTree(pCmap->pScreen, TellGainedMap, (void *)&pCmap->mid); + + nxagentSetInstalledColormapWindows(pCmap->pScreen); + nxagentDirectInstallColormaps(pCmap->pScreen); + } +} + +void nxagentUninstallColormap(ColormapPtr pCmap) +{ + int index; + ColormapPtr pCurCmap; + + index = pCmap->pScreen->myNum; + pCurCmap = InstalledMaps[index]; + + if(pCmap == pCurCmap) + { + if ((unsigned int)pCmap->mid != pCmap->pScreen->defColormap) + { + pCurCmap = (ColormapPtr)LookupIDByType(pCmap->pScreen->defColormap, + RT_COLORMAP); + (*pCmap->pScreen->InstallColormap)(pCurCmap); + } + } +} + +int nxagentListInstalledColormaps(ScreenPtr pScreen, Colormap *pCmapIds) +{ + if (nxagentInstalledDefaultColormap) + { + *pCmapIds = InstalledMaps[pScreen->myNum]->mid; + + return 1; + } + else + { + return 0; + } +} + +void nxagentStoreColors(ColormapPtr pCmap, int nColors, xColorItem *pColors) +{ + if (pCmap->pVisual->class & DynamicClass) +#ifdef _XSERVER64 + { + int i; + XColor *pColors64 = (XColor *)malloc(nColors * sizeof(XColor) ); + + for(i = 0; i < nColors; ++i) + { + pColors64[i].pixel = pColors[i].pixel; + pColors64[i].red = pColors[i].red; + pColors64[i].green = pColors[i].green; + pColors64[i].blue = pColors[i].blue; + pColors64[i].flags = pColors[i].flags; + } + XStoreColors(nxagentDisplay, nxagentColormap(pCmap), pColors64, nColors); + free(pColors64); + } +#else + XStoreColors(nxagentDisplay, nxagentColormap(pCmap), + (XColor *)pColors, nColors); +#endif +} + +void nxagentResolveColor(unsigned short *pRed, unsigned short *pGreen, + unsigned short *pBlue, VisualPtr pVisual) +{ + int shift; + unsigned int lim; + + shift = 16 - pVisual->bitsPerRGBValue; + lim = (1 << pVisual->bitsPerRGBValue) - 1; + + if ((pVisual->class == PseudoColor) || (pVisual->class == DirectColor)) + { + /* rescale to rgb bits */ + *pRed = ((*pRed >> shift) * 65535) / lim; + *pGreen = ((*pGreen >> shift) * 65535) / lim; + *pBlue = ((*pBlue >> shift) * 65535) / lim; + } + else if (pVisual->class == GrayScale) + { + /* rescale to gray then rgb bits */ + *pRed = (30L * *pRed + 59L * *pGreen + 11L * *pBlue) / 100; + *pBlue = *pGreen = *pRed = ((*pRed >> shift) * 65535) / lim; + } + else if (pVisual->class == StaticGray) + { + unsigned int limg; + + limg = pVisual->ColormapEntries - 1; + /* rescale to gray then [0..limg] then [0..65535] then rgb bits */ + *pRed = (30L * *pRed + 59L * *pGreen + 11L * *pBlue) / 100; + *pRed = ((((*pRed * (limg + 1))) >> 16) * 65535) / limg; + *pBlue = *pGreen = *pRed = ((*pRed >> shift) * 65535) / lim; + } + else + { + unsigned limr, limg, limb; + + limr = pVisual->redMask >> pVisual->offsetRed; + limg = pVisual->greenMask >> pVisual->offsetGreen; + limb = pVisual->blueMask >> pVisual->offsetBlue; + /* rescale to [0..limN] then [0..65535] then rgb bits */ + *pRed = ((((((*pRed * (limr + 1)) >> 16) * + 65535) / limr) >> shift) * 65535) / lim; + *pGreen = ((((((*pGreen * (limg + 1)) >> 16) * + 65535) / limg) >> shift) * 65535) / lim; + *pBlue = ((((((*pBlue * (limb + 1)) >> 16) * + 65535) / limb) >> shift) * 65535) / lim; + } +} + +Bool nxagentCreateDefaultColormap(ScreenPtr pScreen) +{ + VisualPtr pVisual; + ColormapPtr pCmap; + unsigned short zero = 0, ones = 0xFFFF; + Pixel wp, bp; + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "Debug: Searching for the root visual [%lu].\n", + pScreen->rootVisual); + #endif + + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++); + + if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &pCmap, + (pVisual->class & DynamicClass) ? AllocNone : AllocAll, 0) + != Success) + return False; + + wp = pScreen->whitePixel; + bp = pScreen->blackPixel; + if ((AllocColor(pCmap, &ones, &ones, &ones, &wp, 0) != + Success) || + (AllocColor(pCmap, &zero, &zero, &zero, &bp, 0) != + Success)) + return FALSE; + pScreen->whitePixel = wp; + pScreen->blackPixel = bp; + (*pScreen->InstallColormap)(pCmap); + + nxagentInstalledDefaultColormap = True; + + return True; +} + +static void nxagentReconnectColormap(void * p0, XID x1, void * p2) +{ + ColormapPtr pCmap = (ColormapPtr)p0; + Bool* pBool = (Bool*)p2; + VisualPtr pVisual; + + #ifdef NXAGENT_RECONNECT_COLORMAP_DEBUG + fprintf(stderr, "nxagentReconnectColormap: %p\n", pCmap); + #endif + + if (!*pBool || !pCmap) + return; + + pVisual = pCmap -> pVisual; + + nxagentColormapPriv(pCmap)->colormap = + XCreateColormap(nxagentDisplay, + nxagentDefaultWindows[pCmap->pScreen->myNum], + nxagentVisual(pVisual), + (pVisual->class & DynamicClass) ? + AllocAll : AllocNone); + + #ifdef NXAGENT_RECONNECT_COLORMAP_DEBUG + fprintf(stderr, "nxagentReconnectColormap: %p - ID %xl\n", + pCmap, nxagentColormap(pCmap)); + #endif +} + +Bool nxagentReconnectAllColormap(void *p0) +{ + int cid; + Bool success = True; + + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_COLORMAP_DEBUG) + fprintf(stderr, "nxagentReconnectAllColormap\n"); + #endif + + for (cid = 0; (cid < MAXCLIENTS) && success; cid++) + { + if (clients[cid] && success) + { + FindClientResourcesByType(clients[cid], RT_COLORMAP, nxagentReconnectColormap, &success); + } + } + + return success; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Colormap.h b/nx-X11/programs/Xserver/hw/nxagent/Colormap.h new file mode 100644 index 000000000..fc3c828f9 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Colormap.h @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Color_H__ +#define __Color_H__ + +#define DUMB_WINDOW_MANAGERS + +#define MAXCMAPS 1 +#define MINCMAPS 1 + +typedef struct { + Colormap colormap; +} nxagentPrivColormap; + +typedef struct { + int numCmapIDs; + Colormap *cmapIDs; + int numWindows; + Window *windows; + int index; +} nxagentInstalledColormapWindows; + +#define nxagentColormapPriv(pCmap) \ + ((nxagentPrivColormap *)((pCmap)->devPriv)) + +#define nxagentColormap(pCmap) (nxagentColormapPriv(pCmap)->colormap) + +#define nxagentPixel(pixel) (pixel) + +Bool nxagentCreateColormap(ColormapPtr pCmap); + +void nxagentDestroyColormap(ColormapPtr pCmap); + +void nxagentSetInstalledColormapWindows(ScreenPtr pScreen); + +void nxagentSetScreenSaverColormapWindow(ScreenPtr pScreen); + +void nxagentDirectInstallColormaps(ScreenPtr pScreen); + +void nxagentDirectUninstallColormaps(ScreenPtr pScreen); + +void nxagentInstallColormap(ColormapPtr pCmap); + +void nxagentUninstallColormap(ColormapPtr pCmap); + +int nxagentListInstalledColormaps(ScreenPtr pScreen, Colormap *pCmapIds); + +void nxagentStoreColors(ColormapPtr pCmap, int nColors, xColorItem *pColors); + +void nxagentResolveColor(unsigned short *pRed, unsigned short *pGreen, + unsigned short *pBlue, VisualPtr pVisual); + +Bool nxagentCreateDefaultColormap(ScreenPtr pScreen); + +#endif /* __Color_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Composite.c b/nx-X11/programs/Xserver/hw/nxagent/Composite.c new file mode 100644 index 000000000..bd84c52b0 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Composite.c @@ -0,0 +1,207 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "scrnintstr.h" +#include "windowstr.h" + +#include "Agent.h" +#include "Screen.h" +#include "Display.h" +#include "Options.h" +#include "Windows.h" + +#include "X11/include/Xcomposite_nxagent.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Set if the composite extension is supported + * by the remote display. + */ + +int nxagentCompositeEnable = UNDEFINED; + +void nxagentCompositeExtensionInit() +{ + /* + * Set the flag only if the initialization + * completes. + */ + + nxagentCompositeEnable = 0; + + if (nxagentOption(Composite) == 1) + { + int eventBase, errorBase; + + #ifdef TEST + fprintf(stderr, "nxagentCompositeExtensionInit: Checking if the composite extension is supported.\n"); + #endif + + if (XCompositeQueryExtension(nxagentDisplay, &eventBase, &errorBase) == 1) + { + /* + * At the moment we don't need to care + * the version of the extension. + */ + + #ifdef TEST + + int major = -1; + int minor = -1; + + XCompositeQueryVersion(nxagentDisplay, &major, &minor); + + fprintf(stderr, "nxagentCompositeExtensionInit: The remote display supports version [%d] " + "minor [%d].\n", major, minor); + + if (major < 0 || minor < 2) + { + #ifdef WARNING + fprintf(stderr, "nxagentCompositeExtensionInit: WARNING! Potentially incompatible version " + "[%d] minor [%d] detected.\n", major, minor); + #endif + } + + #endif + + #ifdef TEST + fprintf(stderr, "nxagentCompositeExtensionInit: Enabling the use of the composite extension.\n"); + #endif + + nxagentCompositeEnable = 1; + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentCompositeExtensionInit: Composite extension not supported on this display.\n"); + } + #endif + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentRenderExtensionInit: Use of the composite extension not enabled.\n"); + } + #endif +} + +void nxagentRedirectDefaultWindows() +{ + int i; + + if (nxagentOption(Rootless) == 1 || + nxagentCompositeEnable == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentRedirectDefaultWindows: Not redirecting default " + "windows with rootless mode [%d] and composite [%d].\n", + nxagentOption(Rootless), nxagentCompositeEnable); + #endif + + return; + } + + for (i = 0; i < screenInfo.numScreens; i++) + { + WindowPtr pWin = screenInfo.screens[i]->root; + + ScreenPtr pScreen = pWin -> drawable.pScreen; + + #ifdef TEST + fprintf(stderr, "nxagentRedirectDefaultWindows: WARNING! Redirecting default window id [%ld] " + "to off-screen memory.\n", (long int)nxagentDefaultWindows[pScreen->myNum]); + #endif + + /* + * When trying to redirect only the top level window, + * and not the subwindows, we incur in a strange be- + * haviour. The top level is unmapped, mapped, unmap- + * ped and then reparented. This at first makes the + * agent think that the window manager is gone, then + * the agent window disappears. To make thinks even + * more weird, this happens only at reconnection. + */ + + XCompositeRedirectSubwindows(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], + CompositeRedirectAutomatic); + } +} + +void nxagentRedirectWindow(WindowPtr pWin) +{ + if (nxagentOption(Rootless) == 0 || + nxagentCompositeEnable == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentRedirectWindow: Not redirecting window id [%ld] " + "to off-screen memory with rootless mode [%d] and composite [%d].\n", + nxagentWindow(pWin), nxagentOption(Rootless), + nxagentCompositeEnable); + #endif + + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentRedirectWindow: WARNING! Redirecting window id [%ld] " + "to off-screen memory.\n", (long int)nxagentWindow(pWin)); + #endif + + XCompositeRedirectWindow(nxagentDisplay, nxagentWindow(pWin), + CompositeRedirectAutomatic); + + nxagentWindowPriv(pWin) -> isRedirected = 1; +} + +void nxagentUnredirectWindow(WindowPtr pWin) +{ + if (nxagentWindowPriv(pWin) -> isRedirected == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentRedirectWindow: Disabling redirection of window id [%ld] " + "to off-screen memory.\n", nxagentWindow(pWin)); + #endif + + XCompositeUnredirectWindow(nxagentDisplay, nxagentWindow(pWin), + CompositeRedirectAutomatic); + + nxagentWindowPriv(pWin) -> isRedirected = 0; + } + #ifdef WARNING + else + { + fprintf(stderr, "nxagentUnredirectWindow: WARNING! The window id [%ld] " + "was not redirected.\n", (long int)nxagentWindow(pWin)); + } + #endif +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Composite.h b/nx-X11/programs/Xserver/hw/nxagent/Composite.h new file mode 100644 index 000000000..abe2551bf --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Composite.h @@ -0,0 +1,59 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Composite_H__ +#define __Composite_H__ + +/* + * Set if the extension is present and + * its use is enabled. + */ + +extern int nxagentCompositeEnable; + +/* + * Query the composite extension on the + * remote display and set the flag if + * it is supported. + */ + +void nxagentCompositeExtensionInit(void); + +/* + * Let the X server redirect the window + * on the off-screen memory. + */ + +void nxagentRedirectDefaultWindows(void); + +/* + * Enable or disabel the redirection of + * the given window. + */ + +void nxagentRedirectWindow(WindowPtr pWin); +void nxagentUnredirectWindow(WindowPtr pWin); + +#endif /* __Composite_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Cursor.c b/nx-X11/programs/Xserver/hw/nxagent/Cursor.c new file mode 100644 index 000000000..1db26b7ec --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Cursor.c @@ -0,0 +1,600 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include "X.h" +#include "Xproto.h" +#include "screenint.h" +#include "input.h" +#include "misc.h" +#include "cursor.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "servermd.h" +#include "inputstr.h" + +#include "Agent.h" +#include "Display.h" +#include "Options.h" +#include "Screen.h" +#include "Cursor.h" +#include "Image.h" +#include "Visual.h" +#include "Keyboard.h" +#include "Args.h" +#include "Windows.h" +#include "Events.h" +#include "Render.h" +#include "Client.h" + +#include "windowstr.h" +#include "resource.h" + +#include "compext/Compext.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Defined in Display.c. There are huge + * problems mixing the GC definition in + * Xlib with the server code. This must + * be reworked. + */ + +extern XlibGC nxagentBitmapGC; + +/* + * From NXevents.c. + */ + +extern CursorPtr GetSpriteCursor(void); + +void nxagentConstrainCursor(ScreenPtr pScreen, BoxPtr pBox) +{ + #ifdef TEST + + int width, height; + + width = nxagentOption(RootWidth); + height = nxagentOption(RootHeight); + + if (pBox->x1 <= 0 && pBox->y1 <= 0 && + pBox->x2 >= width && pBox->y2 >= height) + { + fprintf(stderr, "nxagentConstrainCursor: Called with box [%d,%d,%d,%d]. " + "Skipping the operation.\n", pBox->x1, pBox->y1, pBox->x2, pBox->y2); + } + else + { + fprintf(stderr, "nxagentConstrainCursor: WARNING! Called with box [%d,%d,%d,%d].\n", + pBox->x1, pBox->y1, pBox->x2, pBox->y2); + } + + #endif +} + +void nxagentCursorLimits(ScreenPtr pScreen, CursorPtr pCursor, + BoxPtr pHotBox, BoxPtr pTopLeftBox) +{ + *pTopLeftBox = *pHotBox; +} + +Bool nxagentDisplayCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + + /* + * Don't define the root cursor + * so that nxagent root window + * inherits the parent's cursor. + */ + + Cursor cursor; + + cursor = (pCursor != rootCursor) ? nxagentCursor(pCursor, pScreen): None; + + if (nxagentOption(Rootless) == False) + { + XDefineCursor(nxagentDisplay, + nxagentInputWindows[pScreen -> myNum], + cursor); + + #ifdef TEST + fprintf(stderr, "nxagentDisplayCursor: Called for cursor at [%p] with private [%p].\n", + (void *) pCursor, pCursor->devPriv[pScreen->myNum]); + #endif + } + + return True; +} + +Bool nxagentRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + XImage *image; + Pixmap source, mask; + XColor fg_color, bg_color; + unsigned long valuemask; + XGCValues values; + + #ifdef TEST + fprintf(stderr, "nxagentRealizeCursor: Called for cursor at [%p].\n", (void *) pCursor); + #endif + + valuemask = GCFunction | + GCPlaneMask | + GCForeground | + GCBackground | + GCClipMask; + + values.function = GXcopy; + values.plane_mask = AllPlanes; + values.foreground = 1L; + values.background = 0L; + values.clip_mask = None; + + XChangeGC(nxagentDisplay, nxagentBitmapGC, valuemask, &values); + + source = XCreatePixmap(nxagentDisplay, + nxagentDefaultWindows[pScreen->myNum], + pCursor->bits->width, + pCursor->bits->height, + 1); + + mask = XCreatePixmap(nxagentDisplay, + nxagentDefaultWindows[pScreen->myNum], + pCursor->bits->width, + pCursor->bits->height, + 1); + + image = XCreateImage(nxagentDisplay, + nxagentDefaultVisual(pScreen), + 1, XYBitmap, 0, + (char *)pCursor->bits->source, + pCursor->bits->width, + pCursor->bits->height, + BitmapPad(nxagentDisplay), 0); + + /* + * If we used nxagentImageNormalize() here, + * we'd swap our own cursor data in place. + * Change byte_order and bitmap_bit_order + * in the image struct to let Xlib do the + * swap for us. + */ + + image -> byte_order = IMAGE_BYTE_ORDER; + image -> bitmap_bit_order = BITMAP_BIT_ORDER; + + NXCleanImage(image); + + XPutImage(nxagentDisplay, source, nxagentBitmapGC, image, + 0, 0, 0, 0, pCursor->bits->width, pCursor->bits->height); + + XFree(image); + + image = XCreateImage(nxagentDisplay, + nxagentDefaultVisual(pScreen), + 1, XYBitmap, 0, + (char *)pCursor->bits->mask, + pCursor->bits->width, + pCursor->bits->height, + BitmapPad(nxagentDisplay), 0); + + image -> byte_order = IMAGE_BYTE_ORDER; + image -> bitmap_bit_order = BITMAP_BIT_ORDER; + + NXCleanImage(image); + + XPutImage(nxagentDisplay, mask, nxagentBitmapGC, image, + 0, 0, 0, 0, pCursor->bits->width, pCursor->bits->height); + + XFree(image); + + fg_color.red = pCursor->foreRed; + fg_color.green = pCursor->foreGreen; + fg_color.blue = pCursor->foreBlue; + + bg_color.red = pCursor->backRed; + bg_color.green = pCursor->backGreen; + bg_color.blue = pCursor->backBlue; + + pCursor->devPriv[pScreen->myNum] = (void *) malloc(sizeof(nxagentPrivCursor)); + + nxagentCursorPriv(pCursor, pScreen)->cursor = + XCreatePixmapCursor(nxagentDisplay, source, mask, &fg_color, + &bg_color, pCursor->bits->xhot, pCursor->bits->yhot); + + nxagentCursorUsesRender(pCursor, pScreen) = 0; + + #ifdef TEST + fprintf(stderr, "nxagentRealizeCursor: Set cursor private at [%p] cursor is [%ld].\n", + (void *) nxagentCursorPriv(pCursor, pScreen), + nxagentCursorPriv(pCursor, pScreen) -> cursor); + #endif + + XFreePixmap(nxagentDisplay, source); + XFreePixmap(nxagentDisplay, mask); + + return True; +} + +Bool nxagentUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + if (nxagentCursorUsesRender(pCursor, pScreen)) + { + PicturePtr pPicture = nxagentCursorPicture(pCursor, pScreen); + + FreePicture(pPicture, pPicture -> id); + } + + if (nxagentCursor(pCursor, pScreen) != None) + { + XFreeCursor(nxagentDisplay, nxagentCursor(pCursor, pScreen)); + + nxagentCursor(pCursor, pScreen) = None; + } + + free(nxagentCursorPriv(pCursor, pScreen)); + + return True; +} + +void nxagentRecolorCursor(ScreenPtr pScreen, CursorPtr pCursor, + Bool displayed) +{ + XColor fg_color, bg_color; + + fg_color.red = pCursor->foreRed; + fg_color.green = pCursor->foreGreen; + fg_color.blue = pCursor->foreBlue; + + bg_color.red = pCursor->backRed; + bg_color.green = pCursor->backGreen; + bg_color.blue = pCursor->backBlue; + + XRecolorCursor(nxagentDisplay, + nxagentCursor(pCursor, pScreen), + &fg_color, &bg_color); +} + +Bool (*nxagentSetCursorPositionW)(ScreenPtr pScreen, int x, int y, + Bool generateEvent); + +Bool nxagentSetCursorPosition(ScreenPtr pScreen, int x, int y, + Bool generateEvent) +{ + if (generateEvent != 0) + { + return (*nxagentSetCursorPositionW)(pScreen, x, y, generateEvent); + } + else + { + /* + * Calling miSetCursorPosition with generateEvent == 0 + * causes a crash in miPoiterUpdate(). + */ + + return 1; + } +} + +void nxagentReconnectCursor(void * p0, XID x1, void * p2) +{ + Bool* pBool = (Bool*)p2; + CursorPtr pCursor = (CursorPtr) p0; + + AnimCurPtr ac; + int j; + + #ifdef TEST + fprintf(stderr, "nxagentReconnectCursor: pCursor at [%p]\n", pCursor); + #endif + + #ifdef NXAGENT_RECONNECT_CURSOR_DEBUG + fprintf(stderr, "nxagentReconnectCursor: pCursor at [%p]\n", pCursor); + #endif + + if (!*pBool || !pCursor) + { + return; + } + + if (nxagentCursorPriv(pCursor, nxagentDefaultScreen) == 0) + { + if (nxagentIsAnimCursor(pCursor)) + { + #ifdef TEST + fprintf(stderr, "nxagentReconnectCursor: nxagentIsAnimCursor pCursor at [%p]\n", pCursor); + #endif + + ac = nxagentGetAnimCursor(pCursor); + + for (j = 0; j < ac->nelt; j++) + { + nxagentReconnectCursor (ac->elts[j].pCursor, x1, p2); + + #ifdef TEST + fprintf(stderr, "nxagentReconnectCursor: Iteration [%d] pCursor at [%p]\n", j, ac->elts[j].pCursor); + #endif + } + } + } + + else + { + if (nxagentCursorUsesRender(pCursor, nxagentDefaultScreen)) + { + PicturePtr pPicture = nxagentCursorPicture(pCursor, nxagentDefaultScreen); + int ret = 1; + + nxagentReconnectPicture(pPicture, 0, &ret); + + nxagentRenderRealizeCursor(nxagentDefaultScreen, pCursor); + } + else + { + free(nxagentCursorPriv(pCursor, nxagentDefaultScreen)); + if (!nxagentRealizeCursor(nxagentDefaultScreen, pCursor)) + { + fprintf(stderr, "nxagentReconnectCursor: nxagentRealizeCursor failed\n"); + *pBool = False; + } + } + } + + #ifdef NXAGENT_RECONNECT_CURSOR_DEBUG + fprintf(stderr, "nxagentReconnectCursor: %p - ID %lx\n", pCursor, nxagentCursor(pCursor, nxagentDefaultScreen)); + #endif +} + +/* + * The parameter is ignored at the moment. + */ + +void nxagentReDisplayCurrentCursor() +{ + CursorPtr pCursor = GetSpriteCursor(); + + if (pCursor && + nxagentCursorPriv(pCursor, nxagentDefaultScreen) && + nxagentCursor(pCursor, nxagentDefaultScreen)) + { + nxagentDisplayCursor(nxagentDefaultScreen, pCursor); + } +} + +Bool nxagentReconnectAllCursor(void *p0) +{ + int i; + Bool r = True; + + GrabPtr grab = inputInfo.pointer -> grab; + + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_CURSOR_DEBUG) + fprintf(stderr, "nxagentReconnectAllCursor\n"); + #endif + + for (i = 0, r = 1; i < MAXCLIENTS; r = 1, i++) + { + if (clients[i]) + { + FindClientResourcesByType(clients[i], RT_CURSOR, nxagentReconnectCursor, &r); + + #ifdef WARNING + + if (r == False) + { + fprintf(stderr, "nxagentReconnectAllCursor: WARNING! Failed to recreate " + "cursor for client [%d].\n", i); + } + + #endif + } + } + + if (grab) + { + nxagentReconnectCursor(grab -> cursor, 0, &r); + } + + return r; +} + +void nxagentDisconnectCursor(void * p0, XID x1, void * p2) +{ + Bool* pBool = (Bool *) p2; + CursorPtr pCursor = (CursorPtr) p0; + + AnimCurPtr ac; + int j; + + if (!*pBool || !pCursor) + { + return; + } + + if (nxagentCursorPriv(pCursor, nxagentDefaultScreen) == 0) + { + if (nxagentIsAnimCursor(pCursor)) + { + #ifdef TEST + fprintf(stderr, "nxagentDisconnectCursor: nxagentIsAnimCursor pCursor at [%p]\n", pCursor); + #endif + + ac = nxagentGetAnimCursor(pCursor); + + for (j = 0; j < ac->nelt; j++) + { + nxagentDisconnectCursor (ac->elts[j].pCursor, x1, p2); + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectCursor: Iteration [%d] pCursor at [%p]\n", j, ac->elts[j].pCursor); + #endif + } + } + return; + } + + #ifdef NXAGENT_RECONNECT_CURSOR_DEBUG + fprintf(stderr, "nxagentDisconnectCursor: %p - ID %lx\n", + pCursor, + nxagentCursor(pCursor, nxagentDefaultScreen)); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectCursor: Called with bool [%d].\n", *pBool); + + fprintf(stderr, "nxagentDisconnectCursor: Pointer to cursor is [%p] with counter [%d].\n", + (void *) pCursor, pCursor -> refcnt); + + fprintf(stderr, "nxagentDisconnectCursor: Dummy screen is at [%p].\n", + (void *) nxagentDefaultScreen); + + fprintf(stderr, "nxagentDisconnectCursor: Cursor private is at [%p].\n", + (void *) nxagentCursorPriv(pCursor, nxagentDefaultScreen)); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectCursor: Dummy screen number is [%d].\n", + nxagentDefaultScreen -> myNum); + + fprintf(stderr, "nxagentDisconnectCursor: Cursor is [%ld].\n", + nxagentCursor(pCursor, nxagentDefaultScreen)); + #endif + + nxagentCursor(pCursor, nxagentDefaultScreen) = None; + + if (nxagentCursorUsesRender(pCursor, nxagentDefaultScreen)) + { + PicturePtr pPicture = nxagentCursorPicture(pCursor, nxagentDefaultScreen); + int ret = 1; + + #if defined(NXAGENT_RECONNECT_CURSOR_DEBUG) || defined(NXAGENT_RECONNECT_PICTURE_DEBUG) + fprintf(stderr, "nxagentDisconnectCursor: disconnecting attached picture %p\n", pPicture); + #endif + + nxagentDisconnectPicture(pPicture, 0, &ret); + } +} + +Bool nxagentDisconnectAllCursor() +{ + int i; + Bool r = True; + + GrabPtr grab = inputInfo.pointer -> grab; + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectAllCursor: Going to iterate through cursor resources.\n"); + #endif + + for (i = 0, r = 1; i < MAXCLIENTS; r = 1, i++) + { + if (clients[i]) + { + FindClientResourcesByType(clients[i], RT_CURSOR, nxagentDisconnectCursor, &r); + + #ifdef WARNING + + if (r == False) + { + fprintf(stderr, "nxagentDisconnectAllCursor: WARNING! Failed to disconnect " + "cursor for client [%d].\n", i); + } + + #endif + } + } + + if (grab) + { + nxagentDisconnectCursor(grab -> cursor, 0, &r); + } + + return r; +} + + +#ifdef NXAGENT_RECONNECT_CURSOR_DEBUG + +void nxagentPrintCursorInfo(CursorPtr pCursor, char msg[]) +{ + fprintf(stderr, "%s: %p - ID %lx - ref count %d\n", + msg, pCursor, nxagentCursor(pCursor, nxagentDefaultScreen), pCursor->refcnt); +} + +void nxagentListCursor(void *p0, void *p1, void *p2) +{ + CursorPtr pCursor = (CursorPtr)p0; + + nxagentPrintCursorInfo(pCursor, "CursorDebug:"); +} + +void nxagentListCursors(void) +{ + int i; + Bool r; + + for (i = 0, r = 1; i < MAXCLIENTS; r = 1, i++) + { + if (clients[i]) + { + FindClientResourcesByType(clients[i], RT_CURSOR, nxagentListCursor, &r); + + #ifdef WARNING + + if (r == False) + { + fprintf(stderr, "nxagentListCursors: WARNING! Failed to list " + "cursor for client [%d].\n", i); + } + + #endif + } + } + + return True; +} + +#endif /* NXAGENT_RECONNECT_CURSOR_DEBUG */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Cursor.h b/nx-X11/programs/Xserver/hw/nxagent/Cursor.h new file mode 100644 index 000000000..b115dfa38 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Cursor.h @@ -0,0 +1,117 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Cursor_H__ +#define __Cursor_H__ + +#include "cursorstr.h" +#include "picturestr.h" + +typedef struct { + Cursor cursor; + PicturePtr picture; + int uses_render; + int x; + int y; +} nxagentPrivCursor; + +/* + * _AnimCurElt and _AnimCur already defined in animcur.c. + */ + +typedef struct _AnimCurElt { + CursorPtr pCursor; + CARD32 delay; +} AnimCurElt; + +typedef struct _AnimCur { + int nelt; + AnimCurElt *elts; +} AnimCurRec, *AnimCurPtr; + +CursorBitsPtr nxagentAnimCursorBits; + +#define nxagentIsAnimCursor(c) ((c)->bits == nxagentAnimCursorBits) +#define nxagentGetAnimCursor(c) ((AnimCurPtr) ((c) + 1)) + +#define nxagentCursorPriv(pCursor, pScreen) \ + ((nxagentPrivCursor *)((pCursor)->devPriv[pScreen->myNum])) + +#define nxagentCursor(pCursor, pScreen) \ + (nxagentCursorPriv(pCursor, pScreen)->cursor) + +#define nxagentCursorPicture(pCursor, pScreen) \ + (nxagentCursorPriv(pCursor, pScreen)->picture) + +#define nxagentCursorUsesRender(pCursor, pScreen) \ + (nxagentCursorPriv(pCursor, pScreen)->uses_render) + +#define nxagentCursorXOffset(pCursor, pScreen) \ + (nxagentCursorPriv(pCursor, pScreen)->x) + +#define nxagentCursorYOffset(pCursor, pScreen) \ + (nxagentCursorPriv(pCursor, pScreen)->y) + +void nxagentConstrainCursor(ScreenPtr pScreen, BoxPtr pBox); + +void nxagentCursorLimits(ScreenPtr pScreen, CursorPtr pCursor, + BoxPtr pHotBox, BoxPtr pTopLeftBox); + +Bool nxagentDisplayCursor(ScreenPtr pScreen, CursorPtr pCursor); + +Bool nxagentRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); + +Bool nxagentUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); + +void nxagentRecolorCursor(ScreenPtr pScreen, CursorPtr pCursor, + Bool displayed); + +Bool nxagentSetCursorPosition(ScreenPtr pScreen, int x, int y, + Bool generateEvent); + +extern Bool (*nxagentSetCursorPositionW)(ScreenPtr pScreen, int x, int y, + Bool generateEvent); + +void nxagentDisconnectCursor(void * p0, XID x1, void * p2); +void nxagentReconnectCursor(void * p0, XID x1, void * p2); +void nxagentReDisplayCurrentCursor(void); +Bool nxagentReconnectAllCursor(void *p0); +Bool nxagentDisconnectAllCursor(void); + +#endif /* __Cursor_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Dialog.c b/nx-X11/programs/Xserver/hw/nxagent/Dialog.c new file mode 100644 index 000000000..b7852a0ac --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Dialog.c @@ -0,0 +1,546 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "scrnintstr.h" +#include "Agent.h" + +#include <nx-X11/Xlib.h> + +#include "opaque.h" + +#include "Args.h" +#include "Display.h" +#include "Dialog.h" + +#include <nx/NX.h> +#include "compext/Compext.h" +#include <nx/NXalert.h> + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int nxagentKillDialogPid = 0; +int nxagentSuspendDialogPid = 0; +int nxagentRootlessDialogPid = 0; +int nxagentPulldownDialogPid = 0; +int nxagentFontsReplacementDialogPid = 0; +int nxagentEnableRandRModeDialogPid = 0; +int nxagentDisableRandRModeDialogPid = 0; +int nxagentEnableDeferModePid = 0; +int nxagentDisableDeferModePid = 0; + +static int nxagentFailedReconnectionDialogPid = 0; + +char nxagentPulldownWindow[16]; + +char nxagentFailedReconnectionMessage[256]; + +void nxagentResetDialog(int pid) +{ + if (pid == nxagentRootlessDialogPid) + { + #ifdef TEST + fprintf(stderr, "nxagentResetDialog: Resetting rootless dialog pid [%d].\n", nxagentRootlessDialogPid); + #endif + + nxagentRootlessDialogPid = 0; + } + else if (pid == nxagentPulldownDialogPid) + { + #ifdef TEST + fprintf(stderr, "nxagentResetDialog: Resetting pulldown dialog pid [%d].\n", nxagentPulldownDialogPid); + #endif + + nxagentPulldownDialogPid = 0; + } + else if (pid == nxagentFontsReplacementDialogPid) + { + #ifdef TEST + fprintf(stderr, "nxagentFontsReplacementDialog: Resetting fonts replacement dialog pid [%d].\n", + nxagentFontsReplacementDialogPid); + #endif + + nxagentFontsReplacementDialogPid = 0; + } + else if (pid == nxagentKillDialogPid) + { + #ifdef TEST + fprintf(stderr, "nxagentResetDialog: Resetting kill dialog pid [%d].\n", nxagentKillDialogPid); + #endif + + nxagentKillDialogPid = 0; + } + else if (pid == nxagentSuspendDialogPid) + { + #ifdef TEST + fprintf(stderr, "nxagentResetDialog: Resetting suspend dialog pid [%d].\n", nxagentSuspendDialogPid); + #endif + + nxagentSuspendDialogPid = 0; + } + else if (pid == nxagentFailedReconnectionDialogPid) + { + #ifdef TEST + fprintf(stderr, "nxagentResetDialog: Resetting Failed Reconnection dialog pid [%d].\n", + nxagentFailedReconnectionDialogPid); + #endif + + nxagentFailedReconnectionDialogPid = 0; + } + else if (pid == nxagentEnableRandRModeDialogPid) + { + #ifdef TEST + fprintf(stderr, "nxagentResetDialog: Resetting RandR mode dialog pid [%d].\n", + nxagentEnableRandRModeDialogPid); + #endif + + nxagentEnableRandRModeDialogPid = 0; + } + else if (pid == nxagentDisableRandRModeDialogPid) + { + #ifdef TEST + fprintf(stderr, "nxagentResetDialog: Resetting NoRandR mode dialog pid [%d].\n", + nxagentDisableRandRModeDialogPid); + #endif + + nxagentDisableRandRModeDialogPid = 0; + } + else if (pid == nxagentEnableDeferModePid) + { + #ifdef TEST + fprintf(stderr, "nxagentResetDialog: Resetting enable defer mode dialog pid [%d].\n", + nxagentEnableDeferModePid); + #endif + + nxagentEnableDeferModePid = 0; + } + else if (pid == nxagentDisableDeferModePid) + { + #ifdef TEST + fprintf(stderr, "nxagentResetDialog: Resetting disable defer mode dialog pid [%d].\n", + nxagentDisableDeferModePid); + #endif + + nxagentDisableDeferModePid = 0; + } +} + +void nxagentLaunchDialog(DialogType dialogType) +{ + char dialogDisplay[256]; + sigset_t set, oldSet; + int *pid; + char *type; + char *message; + int local; + const char *window = NULL; + + switch (dialogType) + { + case DIALOG_KILL_SESSION: + { + message = DIALOG_KILL_SESSION_MESSAGE; + type = DIALOG_KILL_SESSION_TYPE; + local = DIALOG_KILL_SESSION_LOCAL; + pid = &nxagentKillDialogPid; + + break; + } + case DIALOG_SUSPEND_SESSION: + { + message = DIALOG_SUSPEND_SESSION_MESSAGE; + type = DIALOG_SUSPEND_SESSION_TYPE; + local = DIALOG_SUSPEND_SESSION_LOCAL; + pid = &nxagentSuspendDialogPid; + + break; + } + case DIALOG_ROOTLESS: + { + message = DIALOG_ROOTLESS_MESSAGE; + type = DIALOG_ROOTLESS_TYPE; + local = DIALOG_ROOTLESS_LOCAL; + pid = &nxagentRootlessDialogPid; + + break; + } + case DIALOG_PULLDOWN: + { + message = DIALOG_PULLDOWN_MESSAGE; + type = DIALOG_PULLDOWN_TYPE; + local = DIALOG_PULLDOWN_LOCAL; + pid = &nxagentPulldownDialogPid; + window = nxagentPulldownWindow; + + break; + } + case DIALOG_FONT_REPLACEMENT: + { + message = DIALOG_FONT_REPLACEMENT_MESSAGE; + type = DIALOG_FONT_REPLACEMENT_TYPE; + local = DIALOG_FONT_REPLACEMENT_LOCAL; + pid = &nxagentFontsReplacementDialogPid; + + break; + } + case DIALOG_FAILED_RECONNECTION: + { + message = DIALOG_FAILED_RECONNECTION_MESSAGE; + type = DIALOG_FAILED_RECONNECTION_TYPE; + local = DIALOG_FAILED_RECONNECTION_LOCAL; + pid = &nxagentFailedReconnectionDialogPid; + + break; + } + case DIALOG_ENABLE_DESKTOP_RESIZE_MODE: + { + message = DIALOG_ENABLE_DESKTOP_RESIZE_MODE_MESSAGE; + type = DIALOG_ENABLE_DESKTOP_RESIZE_MODE_TYPE; + local = DIALOG_ENABLE_DESKTOP_RESIZE_MODE_LOCAL; + pid = &nxagentEnableRandRModeDialogPid; + + break; + } + case DIALOG_DISABLE_DESKTOP_RESIZE_MODE: + { + message = DIALOG_DISABLE_DESKTOP_RESIZE_MODE_MESSAGE; + type = DIALOG_DISABLE_DESKTOP_RESIZE_MODE_TYPE; + local = DIALOG_DISABLE_DESKTOP_RESIZE_MODE_LOCAL; + pid = &nxagentDisableRandRModeDialogPid; + + break; + } + case DIALOG_ENABLE_DEFER_MODE: + { + message = DIALOG_ENABLE_DEFER_MODE_MESSAGE; + type = DIALOG_ENABLE_DEFER_MODE_TYPE; + local = DIALOG_ENABLE_DEFER_MODE_LOCAL; + pid = &nxagentEnableDeferModePid; + + break; + } + case DIALOG_DISABLE_DEFER_MODE: + { + message = DIALOG_DISABLE_DEFER_MODE_MESSAGE; + type = DIALOG_DISABLE_DEFER_MODE_TYPE; + local = DIALOG_DISABLE_DEFER_MODE_LOCAL; + pid = &nxagentDisableDeferModePid; + + break; + } + default: + { + #ifdef WARNING + fprintf(stderr, "nxagentLaunchDialog: Unknown Dialog type [%d].\n", dialogType); + #endif + + return; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentLaunchDialog: Launching dialog type [%d] message [%s].\n", type, message); + #endif + + if (dialogType == DIALOG_FAILED_RECONNECTION) + { + strncpy(dialogDisplay, nxagentDisplayName, 255); + } + else + { + strcpy(dialogDisplay, ":"); + strncat(dialogDisplay, display, 254); + } + + *(dialogDisplay + 255) = '\0'; + + /* + * We don't want to receive SIGCHLD + * before we store the child pid. + */ + + sigemptyset(&set); + + sigaddset(&set, SIGCHLD); + + sigprocmask(SIG_BLOCK, &set, &oldSet); + + *pid = NXTransDialog(nxagentDialogName, message, window, + type, local, dialogDisplay); + + #ifdef TEST + fprintf(stderr, "nxagentLaunchDialog: Launched dialog %s with pid [%d] on display %s.\n", + DECODE_DIALOG_TYPE(dialogType), *pid, dialogDisplay); + #endif + + *dialogDisplay = '\0'; + + /* + * Restore the previous set of + * blocked signal. + */ + + sigprocmask(SIG_SETMASK, &oldSet, NULL); +} + +void nxagentPulldownDialog(Window wid) +{ + snprintf(nxagentPulldownWindow, 15, "%ld", (long int) wid); + nxagentPulldownWindow[15] = 0; + + #ifdef TEST + fprintf(stderr, "nxagentPulldownDialog: Going to launch pulldown " + "dialog on window [%s].\n", nxagentPulldownWindow); + #endif + + nxagentLaunchDialog(DIALOG_PULLDOWN); + + nxagentPulldownWindow[0] = 0; +} + +void nxagentFailedReconnectionDialog(int alert, char *error) +{ + if (alert == 0) + { + #ifdef WARNING + fprintf(stderr, "nxagentFailedReconnectionDialog: WARNING! No valid alert provided. " + "Using the default.\n"); + #endif + + alert = FAILED_RESUME_DISPLAY_ALERT; + } + + if (NXDisplayError(nxagentDisplay) == 0 && + NXTransRunning(NX_FD_ANY) == 1) + { + NXTransAlert(alert, NX_ALERT_REMOTE); + + /* + * Make it possible to interrupt the + * loop with a signal. + */ + + while (NXDisplayError(nxagentDisplay) == 0 && + NXTransRunning(NX_FD_ANY) == 1) + { + struct timeval timeout; + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + NXTransContinue(&timeout); + } + } + else + { + int pid; + int status; + int options = 0; + + snprintf(nxagentFailedReconnectionMessage, 255, "Reconnection failed: %s", error); + + *(nxagentFailedReconnectionMessage + 255) = '\0'; + + nxagentLaunchDialog(DIALOG_FAILED_RECONNECTION); + + while ((pid = waitpid(nxagentFailedReconnectionDialogPid, &status, options)) == -1 && + errno == EINTR); + + if (pid == -1) + { + if (errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentFailedReconnectionDialog: Got ECHILD waiting for child [%d].\n", + nxagentFailedReconnectionDialogPid); + #endif + + nxagentFailedReconnectionDialogPid = 0; + } + else + { + fprintf(stderr, "nxagentFailedReconnectionDialog: PANIC! Got unexpected error [%s] waiting " + "for child [%d].\n", strerror(errno), nxagentFailedReconnectionDialogPid); + } + } + else if (pid > 0) + { + if (WIFSTOPPED(status)) + { + #ifdef WARNING + fprintf(stderr, "nxagentFailedReconnectionDialog: Child process [%d] was stopped " + "with signal [%d].\n", pid, (WSTOPSIG(status))); + #endif + } + else + { + #ifdef WARNING + + if (WIFEXITED(status)) + { + fprintf(stderr, "nxagentFailedReconnectionDialog: Child process [%d] exited " + "with status [%d].\n", pid, (WEXITSTATUS(status))); + } + else if (WIFSIGNALED(status)) + { + fprintf(stderr, "nxagentFailedReconnectionDialog: Child process [%d] died " + "because of signal [%d].\n", pid, (WTERMSIG(status))); + } + + #endif + + nxagentResetDialog(pid); + } + } + #ifdef WARNING + else if (pid == 0) + { + fprintf(stderr, "nxagentFailedReconnectionDialog: No own child process exited.\n"); + } + #endif + } +} + +void nxagentTerminateDialog(DialogType type) +{ + int pid; + + switch (type) + { + case DIALOG_KILL_SESSION: + { + pid = nxagentKillDialogPid; + + break; + } + case DIALOG_SUSPEND_SESSION: + { + pid = nxagentSuspendDialogPid; + + break; + } + case DIALOG_ROOTLESS: + { + pid = nxagentRootlessDialogPid; + + break; + } + case DIALOG_PULLDOWN: + { + pid = nxagentPulldownDialogPid; + + break; + } + case DIALOG_FONT_REPLACEMENT: + { + pid = nxagentFontsReplacementDialogPid; + + break; + } + case DIALOG_FAILED_RECONNECTION: + { + pid = nxagentFailedReconnectionDialogPid; + + break; + } + case DIALOG_ENABLE_DESKTOP_RESIZE_MODE: + { + pid = nxagentEnableRandRModeDialogPid; + + break; + } + case DIALOG_DISABLE_DESKTOP_RESIZE_MODE: + { + pid = nxagentDisableRandRModeDialogPid; + + break; + } + case DIALOG_ENABLE_DEFER_MODE: + { + pid = nxagentEnableDeferModePid; + + break; + } + case DIALOG_DISABLE_DEFER_MODE: + { + pid = nxagentDisableDeferModePid; + + break; + } + default: + { + #ifdef WARNING + fprintf(stderr, "nxagentTerminateDialog: Unknown dialog type [%d].\n", type); + #endif + + return; + } + } + + if (pid > 0) + { + if (kill(pid, SIGTERM) == -1) + { + #ifdef WARNING + fprintf(stderr, "nxagentTerminateDialog: Failed to terminate dialog pid [%d]: %s.\n", + pid, strerror(errno)); + #endif + } + } + #ifdef DEBUG + else + { + fprintf(stderr, "nxagentTerminateDialog: Dialog type [%d] is not running.\n", + type); + } + #endif +} + +void nxagentTerminateDialogs() +{ + DialogType type; + + #ifdef DEBUG + fprintf(stderr, "nxagentTerminateDialogs: Terminating all the running dialogs.\n"); + #endif + + for (type = DIALOG_FIRST_TAG; type < DIALOG_LAST_TAG; type++) + { + nxagentTerminateDialog(type); + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Dialog.h b/nx-X11/programs/Xserver/hw/nxagent/Dialog.h new file mode 100644 index 000000000..133dee242 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Dialog.h @@ -0,0 +1,216 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Dialog_H__ +#define __Dialog_H__ + +#include "X11/X.h" + +typedef enum +{ + DIALOG_FIRST_TAG, + DIALOG_KILL_SESSION = DIALOG_FIRST_TAG, + DIALOG_SUSPEND_SESSION, + DIALOG_ROOTLESS, + DIALOG_PULLDOWN, + DIALOG_FONT_REPLACEMENT, + DIALOG_ENABLE_DESKTOP_RESIZE_MODE, + DIALOG_DISABLE_DESKTOP_RESIZE_MODE, + DIALOG_FAILED_RECONNECTION, + DIALOG_ENABLE_DEFER_MODE, + DIALOG_DISABLE_DEFER_MODE, + DIALOG_LAST_TAG + +} DialogType; + +extern int nxagentKillDialogPid; +extern int nxagentSuspendDialogPid; +extern int nxagentRootlessDialogPid; +extern int nxagentPulldownDialogPid; +extern int nxagentFontsReplacementDialogPid; +extern int nxagentEnableRandRModeDialogPid; +extern int nxagentDisableRandRModeDialogPid; +extern int nxagentEnableDeferModePid; +extern int nxagentDisableDeferModePid; + +extern char nxagentFailedReconnectionMessage[]; + +extern char nxagentPulldownWindow[]; + +extern void nxagentLaunchDialog(DialogType type); +extern void nxagentResetDialog(int pid); +extern void nxagentTerminateDialog(DialogType type); +extern void nxagentFailedReconnectionDialog(int alert, char *error); +extern void nxagentPulldownDialog(Window); +extern void nxagentTerminateDialogs(void); + +#define nxagentNoDialogIsRunning \ + (nxagentSuspendDialogPid == 0 && \ + nxagentKillDialogPid == 0 && \ + nxagentEnableRandRModeDialogPid == 0 && \ + nxagentDisableRandRModeDialogPid == 0 && \ + nxagentEnableDeferModePid == 0 && \ + nxagentDisableDeferModePid == 0) + +#define DECODE_DIALOG_TYPE(type) \ + ((type) == DIALOG_KILL_SESSION ? "DIALOG_KILL_SESSION" : \ + (type) == DIALOG_SUSPEND_SESSION ? "DIALOG_SUSPEND_SESSION" : \ + (type) == DIALOG_ROOTLESS ? "DIALOG_ROOTLESS" : \ + (type) == DIALOG_PULLDOWN ? "DIALOG_PULLDOWN" : \ + (type) == DIALOG_FONT_REPLACEMENT ? "DIALOG_FONT_REPLACEMENT" : \ + (type) == DIALOG_ENABLE_DESKTOP_RESIZE_MODE ? "DIALOG_ENABLE_DESKTOP_RESIZE_MODE" :\ + (type) == DIALOG_DISABLE_DESKTOP_RESIZE_MODE ? "DIALOG_DISABLE_DESKTOP_RESIZE_MODE" :\ + (type) == DIALOG_FAILED_RECONNECTION ? "DIALOG_FAILED_RECONNECTION" : \ + (type) == DIALOG_ENABLE_DEFER_MODE ? "DIALOG_ENABLE_DEFER_MODE" : \ + (type) == DIALOG_DISABLE_DEFER_MODE ? "DIALOG_DISABLE_DEFER_MODE" : \ + "UNKNOWN_DIALOG") + +/* + * Message to be showed to users when the close + * button is pressed. The right message is chosen + * according if session does or does not run in + * persistent mode. + */ + +#define DIALOG_KILL_SESSION_MESSAGE \ +\ +"\ +Do you really want to close the session?\ +" + +#define DIALOG_KILL_SESSION_TYPE "yesno" + +#define DIALOG_KILL_SESSION_LOCAL 0 + + +#define DIALOG_SUSPEND_SESSION_MESSAGE \ +\ +"\ +Press the disconnect button to disconnect the running session.\n\ +You will be able to resume the session at later time. Press the\n\ +terminate button to exit the session and close all the running\n\ +programs.\ +" + +#define DIALOG_SUSPEND_SESSION_TYPE "yesnosuspend" + +#define DIALOG_SUSPEND_SESSION_LOCAL 0 + + +#define DIALOG_ROOTLESS_MESSAGE \ +\ +"\ +All remote applications have been terminated.\n\ +Do you want to close the session?\ +" + +#define DIALOG_ROOTLESS_TYPE "yesno" + +#define DIALOG_ROOTLESS_LOCAL 0 + + +#define DIALOG_PULLDOWN_MESSAGE \ +\ +nxagentPulldownWindow + +#define DIALOG_PULLDOWN_TYPE "pulldown" + +#define DIALOG_PULLDOWN_LOCAL 0 + + +#define DIALOG_FONT_REPLACEMENT_MESSAGE \ +\ +"\ +Unable to retrieve all the fonts currently in use. \n\ +Missing fonts have been replaced.\ +" + +#define DIALOG_FONT_REPLACEMENT_TYPE "ok" + +#define DIALOG_FONT_REPLACEMENT_LOCAL 0 + + +#define DIALOG_FAILED_RECONNECTION_MESSAGE \ +\ +nxagentFailedReconnectionMessage + +#define DIALOG_FAILED_RECONNECTION_TYPE "ok" + +#define DIALOG_FAILED_RECONNECTION_LOCAL 0 + + +#define DIALOG_ENABLE_DESKTOP_RESIZE_MODE_MESSAGE \ +\ +"\ +The session is now running in desktop resize mode.\n\ +You can resize the desktop by simply dragging the\n\ +desktop window's border. You can press Ctrl+Alt+R\n\ +again to disable this option.\ +" + +#define DIALOG_ENABLE_DESKTOP_RESIZE_MODE_TYPE "ok" + +#define DIALOG_ENABLE_DESKTOP_RESIZE_MODE_LOCAL 0 + +#define DIALOG_DISABLE_DESKTOP_RESIZE_MODE_MESSAGE \ +\ +"\ +The session is now running in viewport mode. You can\n\ +navigate across different areas of the desktop window\n\ +by dragging the desktop with the mouse or by using the\n\ +arrows keys while pressing Ctrl+Alt. Press Ctrl+Alt+R\n\ +again to return to the desktop resize mode.\ +" + +#define DIALOG_DISABLE_DESKTOP_RESIZE_MODE_TYPE "ok" + +#define DIALOG_DISABLE_DESKTOP_RESIZE_MODE_LOCAL 0 + + +#define DIALOG_ENABLE_DEFER_MODE_MESSAGE \ +\ +"\ +Deferred screen updates are now enabled. You can press\n\ +Ctrl+Alt+E again to disable this option.\ +" + +#define DIALOG_ENABLE_DEFER_MODE_TYPE "ok" + +#define DIALOG_ENABLE_DEFER_MODE_LOCAL 0 + + +#define DIALOG_DISABLE_DEFER_MODE_MESSAGE \ +\ +"\ +Deferred screen updates are now disabled. You can press\n\ +Ctrl+Alt+E to enable it again.\ +" + +#define DIALOG_DISABLE_DEFER_MODE_TYPE "ok" + +#define DIALOG_DISABLE_DEFER_MODE_LOCAL 0 + +#endif /* __Dialog_H__ */ + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Display.c b/nx-X11/programs/Xserver/hw/nxagent/Display.c new file mode 100644 index 000000000..c764f50ae --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Display.c @@ -0,0 +1,2963 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include <signal.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h> +#include <time.h> +#include <errno.h> +#include <stdbool.h> + +#include <nx-X11/X.h> +#include <nx-X11/Xproto.h> +#include "screenint.h" +#include "input.h" +#include "misc.h" +#include "scrnintstr.h" +#include "servermd.h" +#include "windowstr.h" +#include "dixstruct.h" + +#ifdef WATCH +#include "unistd.h" +#endif + +#include <nx/NXalert.h> + +#include "Agent.h" +#include "Display.h" +#include "Visual.h" +#include "Options.h" +#include "Error.h" +#include "Init.h" +#include "Args.h" +#include "Image.h" + +#define Pixmap XlibPixmap +#include "Icons.h" +#undef Pixmap + +#include "Render.h" +#include "Font.h" +#include "Reconnect.h" +#include "Events.h" +#include "Dialog.h" +#include "Client.h" +#include "Splash.h" +#include "Screen.h" +#include "Handlers.h" + +#include <nx/NX.h> +#include "compext/Compext.h" + +#include NXAGENT_ICON_NAME +#include X2GOAGENT_ICON_NAME + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef WATCH + +Display *nxagentDisplay = NULL; +XVisualInfo *nxagentVisuals = NULL; +Bool nxagentTrue24 = False; + +int nxagentNumVisuals; +int nxagentXConnectionNumber; + +int nxagentIOErrorHandler(Display *display); + +static Bool nxagentDisplayInfoSaved = False; +static Display *nxagentDisplayBackup = NULL; +static XlibGC nxagentBitmapGCBackup = NULL; +static XVisualInfo *nxagentVisualsRecBackup; +static int nxagentNumVisualsRecBackup; +static int nxagentNumDefaultColormapsRecBackup; +static int *nxagentDepthsRecBackup; +static int nxagentNumDepthsRecBackup; +static int nxagentDefaultDepthRecBackup; +static int nxagentDisplayWidthRecBackup; +static int nxagentDisplayHeightRecBackup; +static Bool nxagentRenderEnableRecBackup; +static Bool *nxagentVisualHasBeenIgnored; + +static enum +{ + NOTHING = 0, + OPENED, + GOT_VISUAL_INFO, + ALLOC_DEF_COLORMAP, + GOT_DEPTH_LIST, + GOT_PIXMAP_FORMAT_LIST, + EVERYTHING_DONE +} reconnectDisplayState; + +int nxagentDefaultVisualIndex; +Colormap *nxagentDefaultColormaps = NULL; +int nxagentNumDefaultColormaps; +int *nxagentDepths = NULL; +int nxagentNumDepths; +XPixmapFormatValues *nxagentPixmapFormats = NULL; +XPixmapFormatValues *nxagentRemotePixmapFormats = NULL; +int nxagentNumPixmapFormats; +int nxagentRemoteNumPixmapFormats; +Pixel nxagentBlackPixel; +Pixel nxagentWhitePixel; +Drawable nxagentDefaultDrawables[MAXDEPTH + 1]; +Pixmap nxagentScreenSaverPixmap; + +/* + * Also used in Cursor.c. There are huge problems + * using GC definition. This is to be reworked. + */ + +XlibGC nxagentBitmapGC; + +/* + * The "confine" window is used in the nxagentConstrainCursor + * procedure. We are currently overriding the original Xnest + * behaviour. It is unclear what this window is used for. + */ + +Window nxagentConfineWindow; + +Pixmap nxagentIconPixmap; +Pixmap nxagentIconShape; +Bool useXpmIcon = False; + +Bool nxagentMakeIcon(Display *display, Pixmap *nxIcon, Pixmap *nxMask); + + +static void nxagentInitVisuals(void); +static void nxagentSetDefaultVisual(void); +static void nxagentInitDepths(void); +static void nxagentInitPixmapFormats(void); + +static int nxagentCheckForDefaultDepthCompatibility(void); +static int nxagentCheckForDepthsCompatibility(void); +static int nxagentCheckForPixmapFormatsCompatibility(void); +static int nxagentInitAndCheckVisuals(int flexibility); +static int nxagentCheckForColormapsCompatibility(int flexibility); + +/* + * Save Internal implementation Also called in Reconnect.c. + */ + +Display *nxagentInternalOpenDisplay(char *display); + +#ifdef NXAGENT_TIMESTAMP +unsigned long startTime; +#endif + +/* + * This is located in connection.c. + */ + +extern void RejectWellKnownSockets(void); + +int nxagentServerOrder() +{ + int whichbyte = 1; + + if (*((char *) &whichbyte)) + return LSBFirst; + + return MSBFirst; +} + +/* + * FIXME: This error handler is not printing anything + * in the session log. This is OK once the session is + * started, because the error is handled by the other + * layers, but not before that point, as the agent + * would die without giving any feedback to the user + * (or, worse, to the NX server). We should check how + * many requests have been handled for this display + * and print a message if the display dies before the + * session is up and running. + */ + +/* + * FIXME: This should be moved to Error.c, The other + * handlers should be probably moved to Handlers.c. + */ + +int nxagentIOErrorHandler(Display *display) +{ + #ifdef TEST + fprintf(stderr, "nxagentIOErrorHandler: Got I/O error with nxagentException.ioError [%d].\n", + nxagentException.ioError); + #endif + + nxagentException.ioError++; + + #ifdef TEST + fprintf(stderr, "nxagentIOErrorHandler: Set nxagentException.ioError to [%d].\n", + nxagentException.ioError); + #endif + + return 1; +} + +/* + * Force a shutdown of any connection attempt + * while connecting to the remote display. + * This is needed to avoid a hang up in case + * of loopback connections to our own listen- + * ing sockets. + */ + +static void nxagentRejectConnection(int signal) +{ + #ifdef TEST + fprintf(stderr, "nxagentRejectConnection: Going to reject client connections.\n"); + #endif + + RejectWellKnownSockets(); + + #ifdef TEST + fprintf(stderr, "nxagentRejectConnection: Setting new alarm to 5 seconds from now.\n"); + #endif + + /* + * A further timeout is unlikely to happen + * in the case of loopback connections. + */ + + alarm(5); +} + +/* + * Ignore the signal if the NX transport is + * not running. + */ + +static void nxagentSigusrHandler(int signal) +{ + #ifdef TEST + fprintf(stderr, "nxagentSigusrHandler: Nothing to do with signal [%d].\n", + signal); + #endif +} + +static void nxagentSighupHandler(int signal) +{ + #ifdef TEST + fprintf(stderr, "nxagentSighupHandler: Handling signal with state [%s] transport [%d] server " + "generation [%ld].\n", DECODE_SESSION_STATE(nxagentSessionState), + NXTransRunning(NX_FD_ANY), serverGeneration); + #endif + + if (signal != SIGHUP) + { + #ifdef PANIC + fprintf(stderr, "nxagentSighupHandler: PANIC! Invalid signal [%d] received in state [%s].\n", + signal, DECODE_SESSION_STATE(nxagentSessionState)); + #endif + + return; + } + + if (dispatchException & DE_TERMINATE) + { + #ifdef TEST + fprintf(stderr, "nxagentSighupHandler: Ignoring the signal while terminating the session.\n"); + #endif + + return; + } + else if (nxagentSessionState == SESSION_UP) + { + if (nxagentOption(Persistent) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSighupHandler: Handling the signal by disconnecting the agent.\n"); + #endif + + nxagentException.sigHup++; + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentSighupHandler: Ignoring the signal with persistency disabled.\n"); + #endif + } + + return; + } + else if (nxagentSessionState == SESSION_STARTING) + { + #ifdef TEST + fprintf(stderr, "nxagentSighupHandler: Handling the signal by aborting the session.\n"); + #endif + + nxagentException.sigHup++; + + return; + } + else if (nxagentSessionState == SESSION_DOWN) + { + if (NXTransRunning(NX_FD_ANY) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSighupHandler: Handling the signal by aborting the reconnection.\n"); + #endif + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentSighupHandler: Handling the signal by resuming the session.\n"); + #endif + } + + nxagentException.sigHup++; + + return; + } + + #ifdef WARNING + fprintf(stderr, "nxagentSighupHandler: WARNING! Ignoring the signal in state [%s].\n", + DECODE_SESSION_STATE(nxagentSessionState)); + #endif +} + +static void nxagentSigchldHandler(int signal) +{ + int pid = 0; + int status; + int options; + + #ifdef TEST + fprintf(stderr, "nxagentSigchldHandler: Going to check the children processes.\n"); + #endif + + options = WNOHANG | WUNTRACED; + + /* + * Try with the pid of the dialog process. + * Leave the other children unaffected. + */ + + if (nxagentRootlessDialogPid) + { + pid = waitpid(nxagentRootlessDialogPid, &status, options); + + if (pid == -1 && errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Got ECHILD waiting for child %d (Rootless dialog).\n", + nxagentRootlessDialogPid); + #endif + + pid = nxagentRootlessDialogPid = 0; + } + } + + if (pid == 0 && nxagentPulldownDialogPid) + { + pid = waitpid(nxagentPulldownDialogPid, &status, options); + + if (pid == -1 && errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Got ECHILD waiting for child %d (Pulldown dialog).\n", + nxagentPulldownDialogPid); + #endif + + pid = nxagentPulldownDialogPid = 0; + } + } + + if (pid == 0 && nxagentKillDialogPid) + { + pid = waitpid(nxagentKillDialogPid, &status, options); + + if (pid == -1 && errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Got ECHILD waiting for child %d (Kill dialog).\n", + nxagentKillDialogPid); + #endif + + pid = nxagentKillDialogPid = 0; + } + } + + if (pid == 0 && nxagentSuspendDialogPid) + { + pid = waitpid(nxagentSuspendDialogPid, &status, options); + + if (pid == -1 && errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Got ECHILD waiting for child %d (Suspend dialog).\n", + nxagentSuspendDialogPid); + #endif + + pid = nxagentSuspendDialogPid = 0; + } + } + + if (pid == 0 && nxagentFontsReplacementDialogPid) + { + pid = waitpid(nxagentFontsReplacementDialogPid, &status, options); + + if (pid == -1 && errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Got ECHILD waiting for child %d (Fonts replacement).\n", + nxagentFontsReplacementDialogPid); + #endif + + pid = nxagentFontsReplacementDialogPid = 0; + } + } + + if (pid == 0 && nxagentEnableRandRModeDialogPid) + { + pid = waitpid(nxagentEnableRandRModeDialogPid, &status, options); + + if (pid == -1 && errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Got ECHILD waiting for child %d (EnableRandRMode dialog).\n", + nxagentEnableRandRModeDialogPid); + #endif + + pid = nxagentEnableRandRModeDialogPid = 0; + } + } + + if (pid == 0 && nxagentDisableRandRModeDialogPid) + { + pid = waitpid(nxagentDisableRandRModeDialogPid, &status, options); + + if (pid == -1 && errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Got ECHILD waiting for child %d (DisableRandRMode dialog).\n", + nxagentDisableRandRModeDialogPid); + #endif + + pid = nxagentDisableRandRModeDialogPid = 0; + } + } + + if (pid == 0 && nxagentEnableDeferModePid) + { + pid = waitpid(nxagentEnableDeferModePid, &status, options); + + if (pid == -1 && errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Got ECHILD waiting for child %d (EnableDeferMode dialog).\n", + nxagentEnableDeferModePid); + #endif + + pid = nxagentEnableDeferModePid = 0; + } + } + + if (pid == 0 && nxagentDisableDeferModePid) + { + pid = waitpid(nxagentDisableDeferModePid, &status, options); + + if (pid == -1 && errno == ECHILD) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Got ECHILD waiting for child %d (DisableDeferMode dialog).\n", + nxagentDisableDeferModePid); + #endif + + pid = nxagentDisableDeferModePid = 0; + } + } + + if (pid == -1) + { + FatalError("Got error '%s' waiting for the child.\n", strerror(errno)); + } + + if (pid > 0) + { + if (WIFSTOPPED(status)) + { + #ifdef WARNING + fprintf(stderr, "nxagentSigchldHandler: Child process [%d] was stopped " + "with signal [%d].\n", pid, (WSTOPSIG(status))); + #endif + } + else + { + #ifdef TEST + + if (WIFEXITED(status)) + { + fprintf(stderr, "nxagentSigchldHandler: Child process [%d] exited " + "with status [%d].\n", pid, (WEXITSTATUS(status))); + } + else if (WIFSIGNALED(status)) + { + fprintf(stderr, "nxagentSigchldHandler: Child process [%d] died " + "because of signal [%d].\n", pid, (WTERMSIG(status))); + } + + #endif + + nxagentResetDialog(pid); + } + } + else if (pid == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSigchldHandler: Forwarding the signal to the NX transport.\n"); + #endif + + NXTransSignal(SIGCHLD, NX_SIGNAL_RAISE); + } + + return; +} + +Display *nxagentInternalOpenDisplay(char *display) +{ + Display *newDisplay; + + struct sigaction oldAction; + struct sigaction newAction; + + int result; + + /* + * Stop the smart schedule timer since + * it uses SIGALRM as we do. + */ + + nxagentStopTimer(); + + /* + * Install the handler rejecting a possible + * loopback connection. + */ +/* +FIXME: Should print a warning if the user tries to let + the agent impersonate the same display as the + display where the agent is supposed to connect. + We actually handle this by means of RejectWell- + KnownSockets() but without giving to the user + a friendly explaination for the error. +*/ + + newAction.sa_handler = nxagentRejectConnection; + + sigfillset(&newAction.sa_mask); + + newAction.sa_flags = 0; + + while (((result = sigaction(SIGALRM, &newAction, + &oldAction)) == -1) && (errno == EINTR)); + + if (result == -1) + { + FatalError("Can't set alarm for rejecting connections."); + } + + alarm(10); + + #ifdef TEST + fprintf(stderr, "nxagentInternalOpenDisplay: Going to open the display [%s].\n", + display); + #endif + + newDisplay = XOpenDisplay(display); + + alarm(0); + + while (((result = sigaction(SIGALRM, &oldAction, + NULL)) == -1) && (errno == EINTR)); + + if (result == -1) + { + FatalError("Can't restore alarm for rejecting connections."); + } + + #ifdef TEST + fprintf(stderr, "nxagentInternalOpenDisplay: Setting the NX flush policy to immediate.\n"); + #endif + + NXSetDisplayPolicy(nxagentDisplay, NXPolicyImmediate); + + #ifdef TEST + fprintf(stderr, "nxagentInternalOpenDisplay: Function returned display at [%p].\n", + (void *) newDisplay); + #endif + + return newDisplay; +} + +static void nxagentDisplayBlockHandler(Display *display, int reason) +{ + if (nxagentDisplay != NULL) + { + /* + * Don't allow the smart schedule to + * interrupt the agent while waiting + * for the remote display. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentDisplayBlockHandler: BLOCK! Stopping the smart schedule timer.\n"); + #endif + + nxagentStopTimer(); + + if (reason == NXBlockRead) + { + #ifdef DEBUG + fprintf(stderr, "nxagentDisplayBlockHandler: BLOCK! Display is blocking for [read].\n"); + #endif + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentDisplayBlockHandler: BLOCK! Display is blocking for [write].\n"); + #endif + + nxagentBlocking = 1; + + if (!SmartScheduleSignalEnable) + { + + /* + * Let the dispatch attend the next + * client. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentDisplayBlockHandler: BLOCK! Yielding with agent blocked.\n"); + #endif + + nxagentDispatch.start = GetTimeInMillis(); + + nxagentDispatch.in = nxagentBytesIn; + nxagentDispatch.out = nxagentBytesOut; + + } + + /* + * Give a chance to the next client. + */ + + isItTimeToYield = 1; + } + } +} + +static void nxagentDisplayWriteHandler(Display *display, int length) +{ + if (nxagentDisplay != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentDisplayWriteHandler: WRITE! Called with [%d] bytes written.\n", + length); + #endif + + /* + * Notify the dispatch handler. + */ + + nxagentDispatchHandler(NULL, 0, length); + + if (nxagentOption(LinkType) == LINK_TYPE_NONE) + { + nxagentFlush = GetTimeInMillis(); + } + } +} + +static CARD32 nxagentRateTime = 5000; +static CARD32 nxagentLastTime; +static unsigned int nxagentRate = 0; + +int nxagentGetDataRate(void) +{ + return nxagentRate; +} + +static void nxagentDisplayFlushHandler(Display *display, int length) +{ + CARD32 time; + + if (nxagentDisplay != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentDisplayFlushHandler: FLUSH! Called with [%d] bytes flushed.\n", + length); + #endif + + nxagentCongestion = NXDisplayCongestion(nxagentDisplay); + + #ifdef TEST + fprintf(stderr, "nxagentDisplayFlushHandler: FLUSH! Current congestion level is [%d].\n", + nxagentCongestion); + #endif + + if (nxagentOption(LinkType) != LINK_TYPE_NONE) + { + nxagentFlush = GetTimeInMillis(); + + time = nxagentFlush; + + time = time - nxagentLastTime; + + if (time < nxagentRateTime) + { + nxagentRate = ((nxagentRate * (nxagentRateTime - time) + + length) * 1000) / nxagentRateTime; + } + else + { + nxagentRate = (length * 1000) / nxagentRateTime; + } + + nxagentLastTime = nxagentFlush; + } + } +} + +static int nxagentDisplayErrorPredicate(Display *display, int error) +{ + #ifdef TEST + fprintf(stderr, "nxagentDisplayErrorPredicate: CHECK! Error is [%d] with [%d][%d][%d][%d][%d].\n", + ((error == 1) || (dispatchException & DE_RESET) != 0 || + (dispatchException & DE_TERMINATE) != 0 || nxagentException.sigHup > 0 || + nxagentException.ioError > 0), error, (dispatchException & DE_RESET) != 0, + (dispatchException & DE_TERMINATE), nxagentException.sigHup > 0, + nxagentException.ioError > 0); + #endif + + if (error == 0) + { + if ((dispatchException & DE_RESET) != 0 || + (dispatchException & DE_TERMINATE)) + { + return 1; + } + else if (nxagentException.sigHup > 0 || + nxagentException.ioError > 0) + { + NXForceDisplayError(display); + + return 1; + } + } + + return error; +} + +void nxagentInstallDisplayHandlers() +{ + /* + * If the display was already opened, be sure + * all structures are freed. + */ + + nxagentResetDisplayHandlers(); + + /* + * We want the Xlib I/O error handler to return, + * instead of quitting the application. Using + * setjmp()/longjmp() leaves the door open to + * unexpected bugs when dealing with interaction + * with the other X server layers. + */ + + NXHandleDisplayError(1); + + NXSetDisplayBlockHandler(nxagentDisplayBlockHandler); + + NXSetDisplayWriteHandler(nxagentDisplayWriteHandler); + + NXSetDisplayFlushHandler(nxagentDisplayFlushHandler, NULL); + + /* + * Override the default Xlib error handler. + */ + + XSetIOErrorHandler(nxagentIOErrorHandler); + + /* + * Let Xlib become aware of our interrupts. In theory + * we don't need to have the error handler installed + * during the normal operations and could simply let + * the dispatcher handle the interrupts. In practice + * it's better to have Xlib invalidating the display + * as soon as possible rather than incurring in the + * risk of entering a loop that doesn't care checking + * the display errors explicitly. + */ + + #ifdef TEST + fprintf(stderr, "nxagentInstallDisplayHandlers: Installing the error function predicate.\n"); + #endif + + NXSetDisplayErrorPredicate(nxagentDisplayErrorPredicate); +} + +void nxagentPostInstallDisplayHandlers() +{ + /* + * This is executed after having opened the + * display, once we know the display address. + */ + + if (nxagentDisplay != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentPostInstallDisplayHandlers: Initializing the NX display internals.\n"); + #endif + + NXInitDisplay(nxagentDisplay); +/* +FIXME: What is the most appropriate number of elements? + + NXInitCache(nxagentDisplay, 128); +*/ + NXInitCache(nxagentDisplay, 256); + + NXSetDisplayFlushHandler(nxagentDisplayFlushHandler, nxagentDisplay); + } + + /* + * Handler for the Xlib protocol errors. + */ + + XSetErrorHandler(nxagentErrorHandler); +} + +void nxagentResetDisplayHandlers() +{ + if (nxagentDisplay != NULL) + { + /* + * Free the internal nxcompext + * structures. + */ + + NXResetDisplay(nxagentDisplay); + + /* + * Remove the display descriptor + * from the listened sockets. + */ + + nxagentRemoveXConnection(); + + /* + * Restart the suspended clients. + */ + + nxagentWakeupByReconnect(); + + nxagentReleaseAllSplits(); + } + + /* + * Reset the display to a healty state. + */ + + nxagentBuffer = 0; + nxagentBlocking = 0; + nxagentCongestion = 0; + + /* + * Reset the counter of synchronization + * requests pending. + */ + + nxagentTokens.soft = 0; + nxagentTokens.hard = 0; + nxagentTokens.pending = 0; + + /* + * Reset the current dispatch information. + */ + + nxagentDispatch.client = UNDEFINED; + nxagentDispatch.in = 0; + nxagentDispatch.out = 0; + nxagentDispatch.start = 0; +} + +void nxagentInstallSignalHandlers() +{ + #ifdef TEST + fprintf(stderr, "nxagentInstallSignalHandlers: Installing the agent signal handlers.\n"); + #endif + + /* + * Keep the default X server's handlers for + * SIGINT and SIGTERM and restore the other + * signals of interest to our defaults. + */ + + struct sigaction newAction; + + int result; + + /* + * By default nxcomp installs its signal handlers. + * We need to ensure that SIGUSR1 and SIGUSR2 are + * ignored if the NX transport is not running. + */ + + newAction.sa_handler = nxagentSigusrHandler; + + sigfillset(&newAction.sa_mask); + + newAction.sa_flags = 0; + + while (((result = sigaction(SIGUSR1, &newAction, + NULL)) == -1) && (errno == EINTR)); + + if (result == -1) + { + FatalError("Can't set the handler for user signal 1."); + } + + while (((result = sigaction(SIGUSR2, &newAction, + NULL)) == -1) && (errno == EINTR)); + + if (result == -1) + { + FatalError("Can't set the handler for user signal 2."); + } + + /* + * Reset the SIGALRM to the default. + */ + + nxagentStopTimer(); + + newAction.sa_handler = SIG_DFL; + + sigfillset(&newAction.sa_mask); + + while (((result = sigaction(SIGALRM, &newAction, + NULL)) == -1) && (errno == EINTR)); + + if (result == -1) + { + FatalError("Can't set the handler for alarm signal."); + } + + /* + * Let the smart schedule set the SIGALRM + * handler again. + */ + + nxagentInitTimer(); + + /* + * Install our own handler for the SIGHUP. + */ + + newAction.sa_handler = nxagentSighupHandler; + + sigfillset(&newAction.sa_mask); + + newAction.sa_flags = 0; + + while (((result = sigaction(SIGHUP, &newAction, + NULL)) == -1) && (errno == EINTR)); + + if (result == -1) + { + FatalError("Can't set the handler for session suspend."); + } + + /* + * We need to be notified about our children. + */ + + newAction.sa_handler = nxagentSigchldHandler; + + sigfillset(&newAction.sa_mask); + + newAction.sa_flags = 0; + + while (((result = sigaction(SIGCHLD, &newAction, + NULL)) == -1) && (errno == EINTR)); + + if (result == -1) + { + FatalError("Can't set the handler for children."); + } +} + +void nxagentPostInstallSignalHandlers() +{ + #ifdef TEST + fprintf(stderr, "nxagentPostInstallSignalHandlers: Dealing with the proxy signal handlers.\n"); + #endif + + /* + * Reconfigure our signal handlers to work well + * with the NX transport. + * + * Let our handlers manage the SIGINT and SIGTERM. + * The following calls will tell the NX transport + * to restore the old handlers (those originally + * installed by us or the X server). + */ + + NXTransSignal(SIGINT, NX_SIGNAL_DISABLE); + NXTransSignal(SIGTERM, NX_SIGNAL_DISABLE); + + /* + * Also tell the proxy to ignore the SIGHUP. + */ + + NXTransSignal(SIGHUP, NX_SIGNAL_DISABLE); + + /* + * Both the proxy and the agent need to catch + * their children, so we'll have to send the + * signal to transport. + */ + + NXTransSignal(SIGCHLD, NX_SIGNAL_DISABLE); + + /* + * Let the NX transport take care of SIGUSR1 + * and SIGUSR2. + */ +} + +void nxagentResetSignalHandlers() +{ + struct sigaction newAction; + + int result; + + memset(&newAction, 0, sizeof(newAction)); + + /* + * Reset the signal handlers + * to a well known state. + */ + + #ifdef TEST + fprintf(stderr, "nxagentResetSignalHandlers: Resetting the agent the signal handlers.\n"); + #endif + + /* + * Reset the SIGALRM to the default. + */ + + nxagentStopTimer(); + + newAction.sa_handler = SIG_DFL; + + sigfillset(&newAction.sa_mask); + + while (((result = sigaction(SIGALRM, &newAction, + NULL)) == -1) && (errno == EINTR)); + + if (result == -1) + { + FatalError("Can't set the handler for alarm signal."); + } + + /* + * Let the smart schedule set the SIGALRM + * handler again. + */ + + nxagentInitTimer(); + +} + +void nxagentOpenDisplay(int argc, char *argv[]) +{ + int i; + + if (!nxagentDoFullGeneration) return; + + #ifdef NXAGENT_TIMESTAMP + + startTime = GetTimeInMillis(); + + fprintf(stderr, "Display: Opening the display on real X server with time [%d] ms.\n", + GetTimeInMillis() - startTime); + + #endif + + /* + * Initialize the reconnector only in the case + * of persistent sessions. + */ + + if (nxagentOption(Persistent)) + { + nxagentInitReconnector(); + } + + if (*nxagentDisplayName == '\0') + { + strncpy(nxagentDisplayName, XDisplayName(NULL), 1023); + + nxagentDisplayName[1023] = '\0'; + } + + nxagentCloseDisplay(); + + nxagentInstallSignalHandlers(); + + nxagentInstallDisplayHandlers(); + + nxagentDisplay = nxagentInternalOpenDisplay(nxagentDisplayName); + + nxagentPostInstallSignalHandlers(); + + nxagentPostInstallDisplayHandlers(); + + if (nxagentDisplay == NULL) + { +/* +FIXME: The agent should never exit the program with a FatalError() + but rather use a specific function that may eventually call + FatalError() on its turn. +*/ + FatalError("Unable to open display '%s'.\n", nxagentDisplayName); + } + + if (nxagentSynchronize) + XSynchronize(nxagentDisplay, True); + + nxagentXConnectionNumber = XConnectionNumber(nxagentDisplay); + + #ifdef TEST + fprintf(stderr, "nxagentOpenDisplay: Display image order is [%d] bitmap order is [%d].\n", + ImageByteOrder(nxagentDisplay), BitmapBitOrder(nxagentDisplay)); + + fprintf(stderr, "nxagentOpenDisplay: Display scanline unit is [%d] scanline pad is [%d].\n", + BitmapUnit(nxagentDisplay), BitmapPad(nxagentDisplay)); + #endif + + #ifdef WATCH + + fprintf(stderr, "nxagentOpenDisplay: Watchpoint 1.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +#1 U 1 1 256 bits (0 KB) -> 150 bits (0 KB) -> 256/1 -> 150/1 = 1.707:1 +#20 1 1 119104 bits (15 KB) -> 28 bits (0 KB) -> 119104/1 -> 28/1 = 4253.714:1 +#98 2 512 bits (0 KB) -> 84 bits (0 KB) -> 256/1 -> 42/1 = 6.095:1 +*/ + + sleep(60); + + #endif + + #ifdef NXAGENT_TIMESTAMP + + fprintf(stderr, "Display: Display on real X server opened with time [%d] ms.\n", + GetTimeInMillis() - startTime); + + #endif + + nxagentUseNXTrans = + nxagentPostProcessArgs(nxagentDisplayName, nxagentDisplay, + DefaultScreenOfDisplay(nxagentDisplay)); + + /* + * Processing the arguments all the timeouts + * have been set. Now we have to change the + * screen-saver timeout. + */ + + nxagentSetScreenSaverTime(); + + nxagentInitVisuals(); + + nxagentNumDefaultColormaps = nxagentNumVisuals; + nxagentDefaultColormaps = (Colormap *)malloc(nxagentNumDefaultColormaps * + sizeof(Colormap)); + + for (i = 0; i < nxagentNumDefaultColormaps; i++) + { + nxagentDefaultColormaps[i] = XCreateColormap(nxagentDisplay, + DefaultRootWindow(nxagentDisplay), + nxagentVisuals[i].visual, + AllocNone); + } + + #ifdef WATCH + + fprintf(stderr, "nxagentOpenDisplay: Watchpoint 4.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +N/A +*/ + + sleep(30); + + #endif + + nxagentBlackPixel = BlackPixel(nxagentDisplay, DefaultScreen(nxagentDisplay)); + nxagentWhitePixel = WhitePixel(nxagentDisplay, DefaultScreen(nxagentDisplay)); + + #ifdef WATCH + + fprintf(stderr, "nxagentOpenDisplay: Watchpoint 5.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +N/A +*/ + + sleep(30); + + #endif + + /* + * Initialize the agent's event mask that will be requested + * for the root and all the top level windows. If the nested + * window is a child of an existing window, we will need to + * receive StructureNotify events. If we are going to manage + * the changes in root window's visibility we'll also need + * VisibilityChange events. + */ + +/* +FIXME: Use of nxagentParentWindow is strongly deprecated. + We need also to clarify which events are selected + in the diferent operating modes. +*/ + + nxagentInitDefaultEventMask(); + + /* + * Initialize the pixmap depths and formats. + */ + + nxagentInitDepths(); + + nxagentInitPixmapFormats(); + (void) nxagentCheckForPixmapFormatsCompatibility(); + + /* + * Create a pixmap for each depth matching the + * local supported formats with format available + * on the remote display. + */ + + nxagentSetDefaultDrawables(); + + #ifdef RENDER + if (nxagentRenderEnable) + { + nxagentRenderExtensionInit(); + } + #endif + + /* + * This GC is referenced in Cursor.c. It can be + * probably removed. + */ + + nxagentBitmapGC = XCreateGC(nxagentDisplay, nxagentDefaultDrawables[1], 0L, NULL); + + /* + * Note that this "confine window" is useless at the + * moment as we reimplement nxagentConstrainCursor() + * to skip the "constrain" stuff. + */ + + #ifdef TEST + fprintf(stderr, "nxagentOpenDisplay: Going to create agent's confine window.\n"); + #endif + + nxagentConfineWindow = XCreateWindow(nxagentDisplay, + DefaultRootWindow(nxagentDisplay), + 0, 0, 1, 1, 0, 0, + InputOnly, + CopyFromParent, + 0L, NULL); + + #ifdef TEST + fprintf(stderr, "nxagentOpenDisplay: Created agent's confine window with id [%ld].\n", + nxagentConfineWindow); + #endif + + if (!(nxagentUserGeometry.flag & XValue)) + { + nxagentChangeOption(RootX, 0); + } + + if (!(nxagentUserGeometry.flag & YValue)) + { + nxagentChangeOption(RootY, 0); + } + + if (nxagentParentWindow == 0) + { + if (!(nxagentUserGeometry.flag & WidthValue)) + { + if (nxagentOption(Fullscreen)) + { + nxagentChangeOption(RootWidth, DisplayWidth(nxagentDisplay, DefaultScreen(nxagentDisplay))); + } + else + { + nxagentChangeOption(RootWidth, 3 * DisplayWidth(nxagentDisplay, + DefaultScreen(nxagentDisplay)) / 4); + } + } + + if (!(nxagentUserGeometry.flag & HeightValue)) + { + if (nxagentOption(Fullscreen)) + { + nxagentChangeOption(RootHeight, DisplayHeight(nxagentDisplay, DefaultScreen(nxagentDisplay))); + } + else + { + nxagentChangeOption(RootHeight, 3 * DisplayHeight(nxagentDisplay, + DefaultScreen(nxagentDisplay)) / 4); + } + } + } + + if (!nxagentUserBorderWidth) + { + nxagentChangeOption(BorderWidth, 1); + } + + nxagentLogoDepth = DefaultDepth(nxagentDisplay, + DefaultScreen(nxagentDisplay) + ); + + nxagentLogoBlack = 0x000000; + nxagentLogoRed = 0xff0000; + nxagentLogoWhite = 0xffffff; + nxagentLogoGray = 0x222222; + + #ifdef WATCH + + fprintf(stderr, "nxagentOpenDisplay: Watchpoint 5.1.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +N/A +*/ + + sleep(30); + + #endif + + useXpmIcon = nxagentMakeIcon(nxagentDisplay, &nxagentIconPixmap, &nxagentIconShape); + + #ifdef WATCH + + fprintf(stderr, "nxagentOpenDisplay: Watchpoint 5.2.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +#84 2 512 bits (0 KB) -> 76 bits (0 KB) -> 256/1 -> 38/1 = 6.737:1 +*/ + + sleep(30); + + #endif + + #ifdef WATCH + + fprintf(stderr, "nxagentOpenDisplay: Watchpoint 6.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +N/A +*/ + + sleep(30); + + #endif + + #ifdef NXAGENT_TIMESTAMP + + fprintf(stderr, "Display: Open of the display finished with time [%d] ms.\n", + GetTimeInMillis() - startTime); + + #endif + + if (nxagentOption(Persistent)) + { + reconnectDisplayState = EVERYTHING_DONE; + } +} + +void nxagentSetDefaultVisual(void) +{ + XVisualInfo vi; + + int i; + + if (nxagentUserDefaultClass || nxagentUserDefaultDepth) + { + nxagentDefaultVisualIndex = UNDEFINED; + + for (i = 0; i < nxagentNumVisuals; i++) + { + if ((!nxagentUserDefaultClass || + nxagentVisuals[i].class == nxagentDefaultClass) + && + (!nxagentUserDefaultDepth || + nxagentVisuals[i].depth == nxagentDefaultDepth)) + { + nxagentDefaultVisualIndex = i; + + break; + } + } + + if (nxagentDefaultVisualIndex == UNDEFINED) + { + FatalError("Unable to find desired default visual.\n"); + } + } + else + { + vi.visualid = XVisualIDFromVisual(DefaultVisual(nxagentDisplay, + DefaultScreen(nxagentDisplay))); + nxagentDefaultVisualIndex = 0; + + for (i = 0; i < nxagentNumVisuals; i++) + { + if (vi.visualid == nxagentVisuals[i].visualid) + { + nxagentDefaultVisualIndex = i; + } + } + } +} + +void nxagentInitVisuals(void) +{ + XVisualInfo vi; + XVisualInfo *viList = NULL; + + long mask; + int i, viNumList; + + mask = VisualScreenMask; + vi.screen = DefaultScreen(nxagentDisplay); + vi.depth = DefaultDepth(nxagentDisplay, DefaultScreen(nxagentDisplay)); + viList = XGetVisualInfo(nxagentDisplay, mask, &vi, &viNumList); + nxagentVisuals = (XVisualInfo *) malloc(viNumList * sizeof(XVisualInfo)); + nxagentNumVisuals = 0; + + for (i = 0; i < viNumList; i++) + { + if (viList[i].depth == vi.depth) + { + if (nxagentVisuals != NULL) + { + memcpy(nxagentVisuals + nxagentNumVisuals, viList + i, sizeof(XVisualInfo)); + } + + #ifdef DEBUG + fprintf(stderr, "nxagentInitVisuals: Visual:\n"); + fprintf(stderr, "\tdepth = %d\n", nxagentVisuals[nxagentNumVisuals].depth); + fprintf(stderr, "\tclass = %d\n", nxagentVisuals[nxagentNumVisuals].class); + fprintf(stderr, "\tmask = (%lu,%lu,%lu)\n", + nxagentVisuals[nxagentNumVisuals].red_mask, + nxagentVisuals[nxagentNumVisuals].green_mask, + nxagentVisuals[nxagentNumVisuals].blue_mask); + fprintf(stderr, "\tcolormap size = %d\n", nxagentVisuals[nxagentNumVisuals].colormap_size); + fprintf(stderr, "\tbits_per_rgb = %d\n", nxagentVisuals[nxagentNumVisuals].bits_per_rgb); + #endif + + nxagentNumVisuals++; + } + } + + if (nxagentVisuals != NULL) + { + nxagentVisuals = (XVisualInfo *) realloc(nxagentVisuals, + nxagentNumVisuals * sizeof(XVisualInfo)); + } + + XFree(viList); + + if (nxagentNumVisuals == 0 || nxagentVisuals == NULL) + { + FatalError("Unable to find any visuals.\n"); + } + + nxagentSetDefaultVisual(); +} + +void nxagentInitDepths() +{ + #ifdef TEST + int i; + #endif + + nxagentDepths = XListDepths(nxagentDisplay, DefaultScreen(nxagentDisplay), + &nxagentNumDepths); + + if (nxagentDepths == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentInitDepths: PANIC! Failed to get available depths.\n"); + #endif + + FatalError("Failed to get available depths and pixmap formats."); + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentInitDepths: Got [%d] available depths:\n", + nxagentNumDepths); + + for (i = 0; i < nxagentNumDepths; i++) + { + fprintf(stderr, " [%d]", nxagentDepths[i]); + } + + fprintf(stderr, ".\n"); + } + #endif +} + +void nxagentInitPixmapFormats() +{ + int i, j; + int depth; + + /* + * Formats are created with no care of which are supported + * on the real display. Creating only formats supported + * by the remote end makes troublesome handling migration + * of session from a display to another. + */ + + nxagentNumPixmapFormats = 0; + +/* +XXX: Some X server doesn't list 1 among available depths... +*/ + + nxagentPixmapFormats = malloc((nxagentNumDepths + 1) * sizeof(XPixmapFormatValues)); + + for (i = 1; i <= MAXDEPTH; i++) + { + depth = 0; + + if (i == 1) + { + depth = 1; + } + else + { + for (j = 0; j < nxagentNumDepths; j++) + { + if (nxagentDepths[j] == i) + { + depth = i; + + break; + } + } + } + + if (depth != 0) + { + if (nxagentNumPixmapFormats >= MAXFORMATS) + { + FatalError("nxagentInitPixmapFormats: MAXFORMATS is too small for this server.\n"); + } + + nxagentPixmapFormats[nxagentNumPixmapFormats].depth = depth; + nxagentPixmapFormats[nxagentNumPixmapFormats].bits_per_pixel = nxagentBitsPerPixel(depth); + nxagentPixmapFormats[nxagentNumPixmapFormats].scanline_pad = BITMAP_SCANLINE_PAD; + + #ifdef TEST + fprintf(stderr, "nxagentInitPixmapFormats: Set format [%d] to depth [%d] " + "bits per pixel [%d] scanline pad [%d].\n", nxagentNumPixmapFormats, + depth, nxagentPixmapFormats[nxagentNumPixmapFormats].bits_per_pixel, + BITMAP_SCANLINE_PAD); + #endif + + nxagentNumPixmapFormats++; + } + } + + nxagentRemotePixmapFormats = XListPixmapFormats(nxagentDisplay, &nxagentRemoteNumPixmapFormats); + + if (nxagentRemotePixmapFormats == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentInitPixmapFormats: WARNING! Failed to get available remote pixmap formats.\n"); + #endif + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentInitPixmapFormats: Got [%d] available remote pixmap formats:\n", + nxagentRemoteNumPixmapFormats); + + for (i = 0; i < nxagentRemoteNumPixmapFormats; i++) + { + fprintf(stderr, "nxagentInitPixmapFormats: Remote pixmap format [%d]: depth [%d] " + "bits_per_pixel [%d] scanline_pad [%d].\n", i, nxagentRemotePixmapFormats[i].depth, + nxagentRemotePixmapFormats[i].bits_per_pixel, nxagentRemotePixmapFormats[i].scanline_pad); + } + } + #endif +} + +void nxagentSetDefaultDrawables() +{ + int i, j; + + for (i = 0; i <= MAXDEPTH; i++) + { + nxagentDefaultDrawables[i] = None; + } + + for (i = 0; i < nxagentNumPixmapFormats; i++) + { + #ifdef TEST + fprintf(stderr, "nxagentSetDefaultDrawables: Checking remote pixmap format [%d] with depth [%d] " + "bits per pixel [%d] scanline pad [%d].\n", i, nxagentPixmapFormats[i].depth, + nxagentPixmapFormats[i].bits_per_pixel, nxagentPixmapFormats[i].scanline_pad); + #endif + + if (nxagentPixmapFormats[i].depth == 24) + { + if (nxagentPixmapFormats[i].bits_per_pixel == 24) + { + #ifdef TEST + fprintf(stderr, "nxagentSetDefaultDrawables: WARNING! Assuming remote pixmap " + "format [%d] as true 24 bits.\n", i); + #endif + + nxagentTrue24 = True; + } + } + + for (j = 0; j < nxagentNumDepths; j++) + { + #ifdef TEST + fprintf(stderr, "nxagentSetDefaultDrawables: Checking depth at index [%d] with pixmap depth [%d] " + "and display depth [%d].\n", j, nxagentPixmapFormats[i].depth, nxagentDepths[j]); + #endif + + if ((nxagentPixmapFormats[i].depth == 1 || + nxagentPixmapFormats[i].depth == nxagentDepths[j]) && + nxagentDefaultDrawables[nxagentPixmapFormats[i].depth] == None) + { + nxagentDefaultDrawables[nxagentPixmapFormats[i].depth] = + XCreatePixmap(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + 1, 1, nxagentPixmapFormats[i].depth); + + #ifdef TEST + fprintf(stderr, "nxagentSetDefaultDrawables: Created default drawable [%lu] for depth [%d].\n", + nxagentDefaultDrawables[nxagentPixmapFormats[i].depth], nxagentPixmapFormats[i].depth); + #endif + } + } + + if (nxagentDefaultDrawables[nxagentPixmapFormats[i].depth] == None) + { + #ifdef TEST + fprintf(stderr, "nxagentSetDefaultDrawables: WARNING! Forcing default drawable for depth [%d].\n", + nxagentPixmapFormats[i].depth); + #endif + + nxagentDefaultDrawables[nxagentPixmapFormats[i].depth] = + XCreatePixmap(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + 1, 1, nxagentPixmapFormats[i].depth); + + #ifdef TEST + fprintf(stderr, "nxagentSetDefaultDrawables: Created default drawable [%lu] for depth [%d].\n", + nxagentDefaultDrawables[nxagentPixmapFormats[i].depth], nxagentPixmapFormats[i].depth); + #endif + } + } +} + +void nxagentCloseDisplay() +{ + #ifdef TEST + fprintf(stderr, "nxagentCloseDisplay: Called with full generation [%d] and display [%p].\n", + nxagentDoFullGeneration, (void *) nxagentDisplay); + #endif + + if (nxagentDoFullGeneration == 0 || + nxagentDisplay == NULL) + { + return; + } + + /* + * If nxagentDoFullGeneration is true, all + * the X resources will be destroyed upon + * closing the display connection, so there + * is no real need to generate additional + * traffic + */ + + free(nxagentDefaultColormaps); + nxagentDefaultColormaps = NULL; + + XFree(nxagentVisuals); + nxagentVisuals = NULL; + + free(nxagentDepths); + nxagentDepths = NULL; + + XFree(nxagentPixmapFormats); + nxagentPixmapFormats = NULL; + + XFree(nxagentRemotePixmapFormats); + nxagentRemotePixmapFormats = NULL; + + nxagentFreeFontCache(); +/* +FIXME: Is this needed? + + nxagentFreeFontMatchStuff(); +*/ + + /* + * Free the image cache. This is useful + * for detecting memory leaks. + */ + + if (nxagentDisplay != NULL) + { + NXFreeCache(nxagentDisplay); + + NXResetDisplay(nxagentDisplay); + } + + /* + * Kill all the running dialogs. + */ + + nxagentTerminateDialogs(); + + #ifdef TEST + fprintf(stderr, "nxagentCloseDisplay: Setting the display to NULL.\n"); + #endif + + XCloseDisplay(nxagentDisplay); + + nxagentDisplay = NULL; +} + +static FILE *nxagentLookForIconFile(char *iconName, const char *permission, + char *return_path) +{ + char *path; + char *end; + char singlePath[PATH_MAX]; + int breakLoop; + FILE *fptr = NULL; + + #ifdef WIN32 + const char separator = ';'; + const char *slash = "\\"; + #else + const char separator = ':'; + const char *slash = "/"; + #endif + + if ((path = getenv("PATH")) == NULL) + { + return NULL; + } + + for(breakLoop = 0; breakLoop == 0 && fptr == NULL; ) + { + end = strchr(path, separator); + + if (end != NULL) + { + strncpy(singlePath, path, (unsigned long)(end - path)); + + singlePath[(unsigned long)(end - path)] = 0; + + path = end + 1; + } + else + { + strcpy(singlePath, path); + + breakLoop = 1; + } + + if (singlePath[strlen(singlePath)- 1] == slash[0]) + { + singlePath[strlen(singlePath)- 1] = 0; + } + + if (strlen(singlePath) + strlen(iconName) + 1 < PATH_MAX) + { + strncat(singlePath, slash, 1); + strcat(singlePath, iconName); + + if ((fptr = fopen(singlePath, permission)) != NULL) + { + strcpy(return_path, singlePath); + } + } + else + { + fprintf(stderr, "Error: Path too long.\n"); + } + } + + return fptr; +} + +Bool nxagentMakeIcon(Display *display, Pixmap *nxIcon, Pixmap *nxMask) +{ + char default_path [PATH_MAX]; + char icon_path [PATH_MAX]; + FILE *icon_fp; + int status; + Bool success = False; + XlibPixmap IconPixmap; + XlibPixmap IconShape; + char* agent_icon_name; + char** agentIconData; + + /* + * selecting x2go icon when running as X2Go agent + */ + if(nxagentX2go) + { + agent_icon_name=X2GOAGENT_ICON_NAME; + agentIconData=x2goagentIconData; + } + else + { + agent_icon_name=NXAGENT_ICON_NAME; + agentIconData=nxagentIconData; + } + + + snprintf(default_path, PATH_MAX-1, "/usr/NX/share/images/%s", agent_icon_name); + + if ((icon_fp = fopen(default_path, "r")) == NULL) + { + icon_fp = nxagentLookForIconFile(agent_icon_name, "r", icon_path); + + if (icon_fp != NULL) + { + fclose (icon_fp); + success = True; + } + } + else + { + fclose (icon_fp); + success = True; + strcpy(icon_path, default_path); + } + + if (success) + { + status = XpmReadFileToPixmap(display, + DefaultRootWindow(display), + icon_path, + &IconPixmap, + &IconShape, + NULL); + + if (status != XpmSuccess) + { + #ifdef TEST + fprintf(stderr, "nxagentMakeIcon: Xpm operation failed with error '%s'.\n", + XpmGetErrorString(status)); + #endif + + success = False; + } + } + + if (!success) + { + status = XpmCreatePixmapFromData(display, + DefaultRootWindow(display), + agentIconData, + &IconPixmap, + &IconShape, + NULL); + + if (status != XpmSuccess) + { + #ifdef TEST + fprintf(stderr, "nxagentMakeIcon: Xpm operation failed with error '%s'.\n", + XpmGetErrorString(status)); + #endif + + success = False; + } + else + { + success = True; + } + } + + + *nxIcon = IconPixmap; + *nxMask = IconShape; + + return success; +} + +Bool nxagentXServerGeometryChanged() +{ + return (WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) != + WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplayBackup))) || + (HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) != + HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplayBackup))); +} + +void nxagentBackupDisplayInfo(void) +{ + if (nxagentDisplayInfoSaved) + { + return; + } + + /* + * Since we need the display structure + * in order to behave correctly when no X + * connection is available, we must always + * have a good display record. + * It can be discarded only when a new X + * connection is available, so we store it + * in order to destroy whenever the recon- + * nection succed. + */ + + nxagentDisplayBackup = nxagentDisplay; + nxagentBitmapGCBackup = nxagentBitmapGC; + nxagentDepthsRecBackup = nxagentDepths; + nxagentNumDepthsRecBackup = nxagentNumDepths; + nxagentNumDefaultColormapsRecBackup = nxagentNumDefaultColormaps; + nxagentVisualsRecBackup = nxagentVisuals; + nxagentNumVisualsRecBackup = nxagentNumVisuals; + if (nxagentVisualHasBeenIgnored) + { + free(nxagentVisualHasBeenIgnored); + nxagentVisualHasBeenIgnored = NULL; + } + nxagentVisualHasBeenIgnored = malloc(nxagentNumVisuals * sizeof(Bool)); + nxagentDefaultDepthRecBackup = DefaultDepth(nxagentDisplay, DefaultScreen(nxagentDisplay)); + nxagentDisplayWidthRecBackup = DisplayWidth(nxagentDisplay, DefaultScreen(nxagentDisplay)); + nxagentDisplayHeightRecBackup = DisplayHeight(nxagentDisplay, DefaultScreen(nxagentDisplay)); + nxagentRenderEnableRecBackup = nxagentRenderEnable; + + nxagentDisplayInfoSaved = True; +} + +void nxagentCleanupBackupDisplayInfo(void) +{ + free(nxagentDepthsRecBackup); + nxagentNumDepthsRecBackup = 0; + + nxagentNumDefaultColormapsRecBackup = 0; + + free(nxagentVisualsRecBackup); + nxagentNumVisualsRecBackup = 0; + + if (nxagentVisualHasBeenIgnored) + { + free(nxagentVisualHasBeenIgnored); + nxagentVisualHasBeenIgnored = NULL; + } + + nxagentDefaultDepthRecBackup = 0; + nxagentDisplayWidthRecBackup = 0; + nxagentDisplayHeightRecBackup = 0; + + if (nxagentDisplayBackup) + { + XCloseDisplay(nxagentDisplayBackup); + + nxagentDisplayBackup = NULL; + } + + if (nxagentBitmapGCBackup) + { + if (nxagentDisplayBackup) + { + XFreeGC(nxagentDisplayBackup, nxagentBitmapGCBackup); + } + else + { + free(nxagentBitmapGCBackup); + } + + nxagentBitmapGCBackup = NULL; + } + + nxagentDisplayInfoSaved = False; +} + +void nxagentDisconnectDisplay(void) +{ + switch (reconnectDisplayState) + { + case EVERYTHING_DONE: + if (nxagentBitmapGC && + nxagentBitmapGCBackup && + (nxagentBitmapGC != nxagentBitmapGCBackup)) + { + XFreeGC(nxagentDisplay, nxagentBitmapGC); + } + + nxagentBitmapGC = nxagentBitmapGCBackup; + case GOT_PIXMAP_FORMAT_LIST: + case GOT_DEPTH_LIST: + case ALLOC_DEF_COLORMAP: + if (nxagentDefaultColormaps) + { + int i; + + for (i = 0; i < nxagentNumDefaultColormaps; i++) + { + nxagentDefaultColormaps[i] = None; + } + } + case GOT_VISUAL_INFO: + case OPENED: + /* + * Actually we need the nxagentDisplay + * structure in order to let the agent + * go when no X connection is available. + */ + + if (nxagentDisplay && + nxagentDisplayBackup && + (nxagentDisplay != nxagentDisplayBackup)) + { + XCloseDisplay(nxagentDisplay); + } + case NOTHING: + nxagentDisplay = nxagentDisplayBackup; + break; + default: + FatalError("Display is in unknown state. Can't continue."); + } + + reconnectDisplayState = NOTHING; +} + +static int nxagentCheckForDefaultDepthCompatibility() +{ + /* + * Depending on the (reconnect) tolerance checks value, this + * function checks stricter or looser: + * - Strict means that the old and new default depth values + * must match exactly. + * - Safe or Risky means that the default depth values might differ, + * but the new default depth value must be at least as + * high as the former default depth value. This is + * recommended, because it allows clients with a + * higher default depth value to still connect, but + * not lose functionality. + * - Bypass means that all of these checks are essentially + * deactivated. This is probably a very bad idea. + */ + + int dDepth; + + dDepth = DefaultDepth(nxagentDisplay, DefaultScreen(nxagentDisplay)); + + const unsigned int tolerance = nxagentOption(ReconnectTolerance); + + if (ToleranceChecksBypass <= tolerance) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDefaultDepthCompatibility: WARNING! Not proceeding with any checks, " + "because tolerance [%u] higher than or equal [%u]. New default depth value " + "is [%d], former default depth value is [%d].\n", tolerance, + ToleranceChecksBypass, dDepth, nxagentDefaultDepthRecBackup); + #endif + + return 1; + } + + if (nxagentDefaultDepthRecBackup == dDepth) + { + #ifdef TEST + fprintf(stderr, "nxagentCheckForDefaultDepthCompatibility: New default depth [%d] " + "matches with old default depth.\n", dDepth); + #endif + + return 1; + } + else if ((ToleranceChecksSafe <= tolerance) && (nxagentDefaultDepthRecBackup < dDepth)) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDefaultDepthCompatibility: WARNING! New default depth [%d] " + "higher than the old default depth [%d] at tolerance [%u].\n", dDepth, + nxagentDefaultDepthRecBackup, tolerance); + #endif + + return 1; + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDefaultDepthCompatibility: WARNING! New default depth [%d] " + "doesn't match with old default depth [%d] at tolerance [%u].\n", dDepth, + nxagentDefaultDepthRecBackup, tolerance); + #endif + + return 0; + } +} + +static int nxagentCheckForDepthsCompatibility() +{ + /* + * Depending on the (reconnect) tolerance checks value, this + * function checks stricter or looser: + * - Strict means that the number of old and new depths must + * match exactly and every old depth value must be + * available in the new depth array. + * - Safe means that the number of depths might diverge, + * but all former depth must also be included in the + * new depth array. This is recommended, because + * it allows clients with more depths to still + * connect, but not lose functionality. + * - Risky means that the new depths array is allowed to be + * smaller than the old depths array, but at least + * one depth value must be included in both. + * This is potentially unsafe. + * - Bypass or higher means that all of these checks are + * essentially deactivated. This is a very bad idea. + */ + + const unsigned int tolerance = nxagentOption(ReconnectTolerance); + + if (ToleranceChecksBypass <= tolerance) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! Not proceeding with any checks, " + "because tolerance [%u] higher than or equal [%u]. Number of newly available depths " + "is [%d], number of old depths is [%d].\n", tolerance, ToleranceChecksBypass, + nxagentNumDepths, nxagentNumDepthsRecBackup); + #endif + + return 1; + } + + if ((ToleranceChecksStrict == tolerance) && (nxagentNumDepths != nxagentNumDepthsRecBackup)) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! No tolerance allowed and " + "number of new available depths [%d] doesn't match with number of old " + "depths [%d].\n", nxagentNumDepths, + nxagentNumDepthsRecBackup); + #endif + + return 0; + } + + if ((ToleranceChecksSafe == tolerance) && (nxagentNumDepths < nxagentNumDepthsRecBackup)) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! Tolerance [%u] not " + "high enough and number of new available depths [%d] " + "lower than number of old depths [%d].\n", tolerance, + nxagentNumDepths, nxagentNumDepthsRecBackup); + #endif + + return 0; + } + + /* + * By now the tolerance is either: + * - Strict and both depth numbers match + * - Safe and: + * o the number of old and new depths matches exactly, or + * o the number of old depths is lower than the number + * of new depths + * - Risky + */ + + bool compatible = true; + bool one_match = false; + bool matched = false; + int total_matches = 0; + + /* + * FIXME: within this loop, we try to match all "new" depths + * against the "old" depths. Depending upon the flexibility + * value, either all "new" depths must have a corresponding + * counterpart in the "old" array, or at least one value + * must be included in both. + * Is this safe enough though? + * Shouldn't we better try to match entries in the "old" + * depths array against the "new" depths array, such that + * we know that all "old" values are covered by "new" + * values? Or is it more important that "new" values are + * covered by "old" ones, with potentially more "old" + * values lingering around that cannot be displayed by the + * connected client? + * + * This section probably needs a revisit at some point in time. + */ + for (int i = 0; i < nxagentNumDepths; ++i) + { + matched = false; + + for (int j = 0; j < nxagentNumDepthsRecBackup; ++j) + { + if (nxagentDepths[i] == nxagentDepthsRecBackup[j]) + { + matched = true; + one_match = true; + ++total_matches; + + break; + } + } + + if ((ToleranceChecksRisky > tolerance) && (!matched)) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! Tolerance [%u] too low and " + "failed to match available depth [%d].\n", tolerance, nxagentDepths[i]); + #endif + + compatible = false; + + break; + } + } + + /* + * At Risky tolerance, only one match is necessary to be "compatible". + */ + if (ToleranceChecksRisky == tolerance) + { + compatible = one_match; + } + + int ret = (!(!compatible)); + + if (compatible) + { + #ifdef TEST + fprintf(stderr, "nxagentCheckForDepthsCompatibility: Internal depths match with " + "remote depths at tolerance [%u].\n", tolerance); + #endif + + if (total_matches != nxagentNumDepths) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDepthsCompatibility: only some [%d] of the new depths [%d] " + "match with old depths [%d] at tolerance [%u].\n", total_matches, nxagentNumDepths, + nxagentNumDepthsRecBackup, tolerance); + #endif + } + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForDepthsCompatibility: WARNING! New available depths [%d] don't match " + "with old depths [%d] at tolerance [%u]. Only [%d] depth values matched.\n", + nxagentNumDepths, nxagentNumDepthsRecBackup, tolerance, total_matches); + #endif + } + + return (ret); +} + +static int nxagentCheckForPixmapFormatsCompatibility() +{ + /* + * Depending on the (reconnect) tolerance checks value, this + * function checks stricter or looser: + * - Strict means that the number of internal and external + * pixmap formats must match exactly and every + * internal pixmap format must be available in the + * external pixmap format array. + * - Safe means that the number of pixmap formats might + * diverge, but all internal pixmap formats must + * also be included in the external pixmap formats + * array. This is recommended, because it allows + * clients with more pixmap formats to still connect, + * but not lose functionality. + * - Risky means that the internal pixmap formats array is + * allowed to be smaller than the external pixmap + * formats array, but at least one pixmap format must + * be included in both. This is potentially unsafe. + * - Bypass or higher means that all of these checks are + * essentially deactivated. This is a very bad idea. + */ + + const unsigned int tolerance = nxagentOption(ReconnectTolerance); + + if (ToleranceChecksBypass <= tolerance) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Not proceeding with any checks, " + "because tolerance [%u] higher than or equal [%u]. Number of internally available " + "pixmap formats is [%d], number of externally available pixmap formats is [%d].\n", + tolerance, ToleranceChecksBypass, nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats); + #endif + + return 1; + } + + if ((ToleranceChecksStrict == tolerance) && (nxagentNumPixmapFormats != nxagentRemoteNumPixmapFormats)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! No tolerance allowed and number " + "of internal pixmap formats [%d] doesn't match with number of remote formats [%d].\n", + nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats); + #endif + + return 0; + } + + if ((ToleranceChecksSafe == tolerance) && (nxagentNumPixmapFormats > nxagentRemoteNumPixmapFormats)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Tolerance [%u] too low " + "and number of internal pixmap formats [%d] higher than number of external formats [%d].\n", + tolerance, nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats); + #endif + + return 0; + } + + /* + * By now the tolerance is either: + * - Strict + * - Safe and: + * o the number of internal and external pixmap formats + * matches exactly, or + * o the number of external pixmap formats is higher than + * the number of internal pixmap formats, + * - Risky + */ + + bool compatible = true; + bool matched = false; + int total_matches = 0; + + for (int i = 0; i < nxagentNumPixmapFormats; ++i) + { + matched = false; + + for (int j = 0; j < nxagentRemoteNumPixmapFormats; ++j) + { + if (nxagentPixmapFormats[i].depth == nxagentRemotePixmapFormats[j].depth && + nxagentPixmapFormats[i].bits_per_pixel == nxagentRemotePixmapFormats[j].bits_per_pixel && + nxagentPixmapFormats[i].scanline_pad == nxagentRemotePixmapFormats[j].scanline_pad) + { + matched = true; + ++total_matches; + + break; + } + } + + if ((ToleranceChecksRisky > tolerance) && (!matched)) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Tolerance [%u] too low " + "and failed to match internal pixmap format (depth [%d] bpp [%d] pad [%d]).\n", + tolerance, nxagentPixmapFormats[i].depth, nxagentPixmapFormats[i].bits_per_pixel, + nxagentPixmapFormats[i].scanline_pad); + #endif + + compatible = false; + } + } + + int ret = !(!(compatible)); + + if (compatible) + { + #ifdef TEST + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: Internal pixmap formats match with " + "remote pixmap formats at tolerance [%u].\n", tolerance); + #endif + + if (total_matches != nxagentNumPixmapFormats) + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: Only some [%d] of the internal " + "pixmap formats [%d] match with external pixmap formats [%d] at tolerance [%u].\n", + total_matches, nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats, tolerance); + #endif + } + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForPixmapFormatsCompatibility: WARNING! Internally available " + "pixmap formats [%d] don't match with external pixmap formats [%d] " + "at tolerance [%u]. Only [%d] depth values matched.\n", + nxagentNumPixmapFormats, nxagentRemoteNumPixmapFormats, tolerance, total_matches); + #endif + } + + return (ret); +} + +static int nxagentInitAndCheckVisuals(int flexibility) +{ + /* FIXME: does this also need work? */ + XVisualInfo viTemplate; + XVisualInfo *viList; + XVisualInfo *newVisuals; + + long viMask; + int i, n; + int matched; + int compatible; + int viNumList; + + compatible = 1; + + viMask = VisualScreenMask; + viTemplate.screen = DefaultScreen(nxagentDisplay); + viTemplate.depth = DefaultDepth(nxagentDisplay, DefaultScreen(nxagentDisplay)); + viList = XGetVisualInfo(nxagentDisplay, viMask, &viTemplate, &viNumList); + + newVisuals = malloc(sizeof(XVisualInfo) * nxagentNumVisuals); + + for (i = 0; i < nxagentNumVisuals; i++) + { + matched = 0; + + for (n = 0; n < viNumList; n++) + { + if (nxagentCompareVisuals(nxagentVisuals[i], viList[n]) == 1) + { +/* +FIXME: Should the visual be ignored in this case? + We can flag the visuals with inverted masks, + and use this information to switch the masks + when contacting the remote X server. +*/ + if (nxagentVisuals[i].red_mask == viList[n].blue_mask && + nxagentVisuals[i].blue_mask == viList[n].red_mask) + { + #ifdef WARNING + fprintf(stderr, "nxagentInitAndCheckVisuals: WARNING! Red and blue mask inverted. " + "Forcing matching.\n"); + #endif + } + + matched = 1; + + nxagentVisualHasBeenIgnored[i] = FALSE; + + memcpy(newVisuals + i, viList + n, sizeof(XVisualInfo)); + + break; + } + } + + if (matched == 0) + { + if (nxagentVisuals[i].class == DirectColor) + { + #ifdef WARNING + fprintf(stderr, "nxagentInitAndCheckVisuals: WARNING! Ignoring not matched DirectColor visual.\n"); + #endif + + nxagentVisualHasBeenIgnored[i] = TRUE; + + memcpy(newVisuals + i, nxagentVisuals + i, sizeof(XVisualInfo)); + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentInitAndCheckVisuals: WARNING! Failed to match this visual:\n"); + fprintf(stderr, "\tdepth = %d\n", nxagentVisuals[i].depth); + fprintf(stderr, "\tclass = %d\n", nxagentVisuals[i].class); + fprintf(stderr, "\tmask = (%ld,%ld,%ld)\n", + nxagentVisuals[i].red_mask, + nxagentVisuals[i].green_mask, + nxagentVisuals[i].blue_mask); + fprintf(stderr, "\tcolormap size = %d\n", nxagentVisuals[i].colormap_size); + fprintf(stderr, "\tbits_per_rgb = %d\n", nxagentVisuals[i].bits_per_rgb); + #endif + + compatible = 0; + + break; + } + } + } + + XFree(viList); + + if (compatible == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentInitAndCheckVisuals: New visuals match with old visuals.\n"); + #endif + + nxagentVisuals = newVisuals; + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentInitAndCheckVisuals: New visuals don't match with old visuals.\n"); + #endif + + free(newVisuals); + } + + return compatible; +} + +static int nxagentCheckForColormapsCompatibility(int flexibility) +{ + /* FIXME: does this also need work? */ + if (nxagentNumDefaultColormaps == nxagentNumDefaultColormapsRecBackup) + { + #ifdef TEST + fprintf(stderr, "nxagentCheckForColormapsCompatibility: Number of new colormaps [%d] " + "matches with old colormaps.\n", nxagentNumDefaultColormaps); + #endif + + return 1; + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckForColormapsCompatibility: WARNING! Number of new colormaps [%d] " + "doesn't match with old colormaps [%d].\n", nxagentNumDefaultColormaps, + nxagentNumDefaultColormapsRecBackup); + #endif + + return 0; + } +} + +Bool nxagentReconnectDisplay(void *p0) +{ + int i; + int flexibility = *(int*)p0; + + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_DISPLAY_DEBUG) + fprintf(stderr, "nxagentReconnectDisplay\n"); + #endif + + if (reconnectDisplayState) + { + fprintf(stderr, "nxagentReconnectDisplay: Trying to reconnect a session " + "uncleanly disconnected\n"); + + return False; + } + + /* + * Reset the values to their defaults. + */ + + nxagentPackMethod = -1; + nxagentPackQuality = -1; + nxagentSplitThreshold = -1; + + nxagentRemoteMajor = -1; + + nxagentInstallSignalHandlers(); + + nxagentInstallDisplayHandlers(); + + nxagentDisplay = nxagentInternalOpenDisplay(nxagentDisplayName); + + nxagentPostInstallSignalHandlers(); + + nxagentPostInstallDisplayHandlers(); + + if (nxagentDisplay == NULL) + { + nxagentSetReconnectError(FAILED_RESUME_DISPLAY_ALERT, + "Couldn't open the display."); + + return FALSE; + } + + nxagentAddXConnection(); + + /* + * Display is now open. + */ + + reconnectDisplayState = OPENED; + + #ifdef NXAGENT_TIMESTAMP + + fprintf(stderr, "Display: Open of the display finished with time [%d] ms.\n", + GetTimeInMillis() - startTime); + + #endif + + if (nxagentCheckForDefaultDepthCompatibility() == 0) + { + nxagentSetReconnectError(FAILED_RESUME_DISPLAY_ALERT, + "Default display depth doesn't match."); + + return FALSE; + } + + nxagentUseNXTrans = nxagentPostProcessArgs(nxagentDisplayName, nxagentDisplay, + DefaultScreenOfDisplay(nxagentDisplay)); + + /* + * After processing the arguments all the + * timeout values have been set. Now we + * have to change the screen-saver timeout. + */ + + nxagentSetScreenSaverTime(); + + /* + * Init and compare the visuals. + */ + + if (nxagentInitAndCheckVisuals(flexibility) == FALSE) + { + nxagentSetReconnectError(FAILED_RESUME_VISUALS_ALERT, + "Couldn't restore the required visuals."); + + return FALSE; + } + + reconnectDisplayState = GOT_VISUAL_INFO; + + nxagentSetDefaultVisual(); + + nxagentInitAlphaVisual(); + + /* + * Re-allocate the colormaps. + */ + + nxagentNumDefaultColormaps = nxagentNumVisuals; + + nxagentDefaultColormaps = (Colormap *) realloc(nxagentDefaultColormaps, + nxagentNumDefaultColormaps * sizeof(Colormap)); + + if (nxagentDefaultColormaps == NULL) + { + FatalError("Can't allocate memory for the default colormaps\n"); + } + + reconnectDisplayState = ALLOC_DEF_COLORMAP; + + for (i = 0; i < nxagentNumDefaultColormaps; i++) + { + if (nxagentVisualHasBeenIgnored[i]) + { + nxagentDefaultColormaps[i] = (XID)0; + } + else + { + nxagentDefaultColormaps[i] = XCreateColormap(nxagentDisplay, + DefaultRootWindow(nxagentDisplay), + nxagentVisuals[i].visual, + AllocNone); + } + } + + nxagentCheckForColormapsCompatibility(flexibility); + + /* + * Check the display depth. + */ + + nxagentInitDepths(); + + reconnectDisplayState = GOT_DEPTH_LIST; + + if (nxagentCheckForDepthsCompatibility() == 0) + { + nxagentSetReconnectError(FAILED_RESUME_DEPTHS_ALERT, + "Couldn't restore all the required depths."); + + return False; + } + + /* + * nxagentPixmapFormats and nxagentRemotePixmapFormats + * will be reallocated in nxagentInitPixmapFormats(). + */ + + if (nxagentPixmapFormats != NULL) + { + XFree(nxagentPixmapFormats); + + nxagentPixmapFormats = NULL; + } + + if (nxagentRemotePixmapFormats != NULL) + { + XFree(nxagentRemotePixmapFormats); + + nxagentRemotePixmapFormats = NULL; + } + + /* + * Check if all the required pixmap + * formats are supported. + */ + + nxagentInitPixmapFormats(); + + if (nxagentCheckForPixmapFormatsCompatibility() == 0) + { + nxagentSetReconnectError(FAILED_RESUME_PIXMAPS_ALERT, + "Couldn't restore all the required pixmap formats."); + + return False; + } + + reconnectDisplayState = GOT_PIXMAP_FORMAT_LIST; + + /* + * Create a pixmap for each depth matching the + * local supported formats with format available + * on the remote display. + */ + + nxagentSetDefaultDrawables(); + + #ifdef RENDER + + if (nxagentRenderEnable) + { + nxagentRenderExtensionInit(); + } + + if (nxagentRenderEnableRecBackup != nxagentRenderEnable) + { + nxagentRenderEnable = nxagentRenderEnableRecBackup; + + nxagentSetReconnectError(FAILED_RESUME_RENDER_ALERT, + "Render extension not available or incompatible version."); + + return False; + } + + #endif + + nxagentBlackPixel = BlackPixel(nxagentDisplay, DefaultScreen(nxagentDisplay)); + nxagentWhitePixel = WhitePixel(nxagentDisplay, DefaultScreen(nxagentDisplay)); + + /* + * Initialize the agent's event mask that will be requested + * for the root or all the top level windows. If the nested + * window is a child of an existing window we will need to + * receive StructureNotify events. If we are going to manage + * the changes in root window's visibility we'll also need + * VisibilityChange events. + */ + + nxagentInitDefaultEventMask(); + + nxagentBitmapGC = XCreateGC(nxagentDisplay, nxagentDefaultDrawables[1], 0L, NULL); + + #ifdef TEST + fprintf(stderr, "nxagentReconnectDisplay: Going to create agent's confine window.\n"); + #endif + + nxagentConfineWindow = XCreateWindow(nxagentDisplay, + DefaultRootWindow(nxagentDisplay), + 0, 0, 1, 1, 0, 0, + InputOnly, + CopyFromParent, + 0L, NULL); + + #ifdef TEST + fprintf(stderr, "nxagentReconnectDisplay: Created agent's confine window with id [%ld].\n", + nxagentConfineWindow); + #endif + + nxagentLogoDepth = DefaultDepth(nxagentDisplay, DefaultScreen(nxagentDisplay)); + + nxagentLogoBlack = 0x000000; + nxagentLogoRed = 0xff0000; + nxagentLogoWhite = 0xffffff; + nxagentLogoGray = 0x222222; + + useXpmIcon = nxagentMakeIcon(nxagentDisplay, &nxagentIconPixmap, &nxagentIconShape); + + /* + * All went fine. We can continue + * handling our clients. + */ + + reconnectDisplayState = EVERYTHING_DONE; + + return True; +} + +void nxagentAddXConnection() +{ + int fd = XConnectionNumber(nxagentDisplay); + + nxagentXConnectionNumber = fd; + + #ifdef TEST + fprintf(stderr, "nxagentAddXConnection: Adding the X connection [%d] " + "to the device set.\n", nxagentXConnectionNumber); + #endif + + SetNotifyFd(XConnectionNumber(nxagentDisplay), nxagentNotifyConnection, X_NOTIFY_READ, NULL); +} + +void nxagentRemoveXConnection() +{ + #ifdef TEST + fprintf(stderr, "nxagentRemoveXConnection: Removing the X connection [%d] " + "from the device set.\n", nxagentXConnectionNumber); + #endif + + RemoveNotifyFd(nxagentXConnectionNumber); +} + +/* + * Force an I/O error and wait until the NX trans- + * port is gone. It must be called before suspend- + * ing or terminating a session to ensure that the + * NX transport is terminated first. + */ + +void nxagentWaitDisplay() +{ + /* + * Disable the smart scheduler's interrupts. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentWaitDisplay: Stopping the smart schedule timer.\n"); + #endif + + nxagentStopTimer(); + + if (nxagentDisplay != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentWaitDisplay: Going to shutdown the X connection [%d].\n", + nxagentXConnectionNumber); + #endif + + NXForceDisplayError(nxagentDisplay); + + XSync(nxagentDisplay, 0); + } + + #ifdef TEST + fprintf(stderr, "nxagentWaitDisplay: Going to wait for the NX transport.\n"); + #endif + + NXTransDestroy(NX_FD_ANY); + + #ifdef TEST + fprintf(stderr, "nxagentWaitDisplay: The NX transport is not running.\n"); + #endif + + /* + * Be sure the signal handlers are + * in a known state. + */ + + nxagentResetSignalHandlers(); +} + +/* + * This has not to do with the remote display but + * with the X server that the agent is impersonating. + * We have it here to be consistent with the other + * cleanup procedures which have mainly to do with + * the Xlib display connection. + */ + +void nxagentAbortDisplay() +{ + /* + * Be sure the X server socket in .X11-unix is + * deleted otherwise other users may to become + * unable to run a session on the same display. + */ + + #ifdef TEST + fprintf(stderr, "nxagentAbortDisplay: Cleaning up the X server sockets.\n"); + #endif + + CloseWellKnownConnections(); +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Display.h b/nx-X11/programs/Xserver/hw/nxagent/Display.h new file mode 100644 index 000000000..759b0de35 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Display.h @@ -0,0 +1,178 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Display_H__ +#define __Display_H__ + +#define MAXDEPTH 32 +#define MAXVISUALSPERDEPTH 256 + +extern Display *nxagentDisplay; +extern Display *nxagentShadowDisplay; +extern XVisualInfo *nxagentVisuals; +extern int nxagentNumVisuals; +extern int nxagentDefaultVisualIndex; +extern Colormap *nxagentDefaultColormaps; +extern int nxagentNumDefaultColormaps; +extern int *nxagentDepths; +extern int nxagentNumDepths; +extern XPixmapFormatValues *nxagentPixmapFormats; +extern int nxagentNumPixmapFormats; +extern Pixel nxagentBlackPixel; +extern Pixel nxagentWhitePixel; +extern Drawable nxagentDefaultDrawables[MAXDEPTH + 1]; +extern Pixmap nxagentScreenSaverPixmap; + +/* + * The "confine" window is used in nxagentConstrainCursor(). + * We are currently overriding the original Xnest behaviour + * and just skip the "constrain" stuff. + */ + +extern Window nxagentConfineWindow; + +/* + * Keyboard and pointer are handled as they were hardware + * devices, that is we translate the key codes according to + * our own transcripts. We inherit this behaviour from Xnest. + * The following mask will contain the event mask selected + * for the root window. All the keyboard and pointer events + * are enqueued to the mi that translates and posts them to + * managed clients. + */ + +extern unsigned long nxagentEventMask; + +void nxagentOpenDisplay(int argc, char *argv[]); +void nxagentWaitDisplay(void); +void nxagentCloseDisplay(void); +void nxagentAbortDisplay(void); + +void nxagentAddXConnection(void); +void nxagentRemoveXConnection(void); + +Bool nxagentXServerGeometryChanged(void); + +/* + * Create the default drawables. + */ + +void nxagentGetDepthsAndPixmapFormats(void); +void nxagentSetDefaultDrawables(void); + +extern Bool nxagentTrue24; + +void nxagentBackupDisplayInfo(void); +void nxagentCleanupBackupDisplayInfo(void); + +void nxagentInstallDisplayHandlers(void); +void nxagentPostInstallDisplayHandlers(void); +void nxagentResetDisplayHandlers(void); + +void nxagentInstallSignalHandlers(void); +void nxagentPostInstallSignalHandlers(void); +void nxagentResetSignalHandlers(void); + +void nxagentDisconnectDisplay(void); +Bool nxagentReconnectDisplay(void *p0); + +/* + * Deal with the smart scheduler. + */ + +#if HAVE_SETITIMER +#define nxagentInitTimer() \ +\ + SmartScheduleInit(); + +#define nxagentStopTimer() \ +\ + SmartScheduleStopTimer(); \ + +#define nxagentStartTimer() \ +\ + SmartScheduleStartTimer(); + +#define nxagentDisableTimer() \ +\ + SmartScheduleStopTimer(); \ + SmartScheduleSignalEnable = FALSE; +#else +#define nxagentInitTimer() +#define nxagentStopTimer() +#define nxagentStartTimer() +#define nxagentDisableTimer() +#endif /* HAVE_SETITIMER */ + +/* + * File descriptor currently used by + * Xlib for the agent display. + */ + +extern int nxagentXConnectionNumber; + +/* + * File descriptor currently used by + * Xlib for the agent shadow display. + */ + +extern int nxagentShadowXConnectionNumber; + +int nxagentServerOrder(void); + +int nxagentGetDataRate(void); + +#define nxagentClientOrder(client) \ + ((client)->swapped ? !nxagentServerOrder() : nxagentServerOrder()) + +/* + * Terminate the agent after the next + * dispatch loop. + */ + +#define nxagentTerminateSession() \ + do \ + { \ + dispatchException |= DE_TERMINATE; \ + \ + isItTimeToYield = TRUE; \ + } \ + while (0) + +#endif /* __Display_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Drawable.c b/nx-X11/programs/Xserver/hw/nxagent/Drawable.c new file mode 100644 index 000000000..917f460ba --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Drawable.c @@ -0,0 +1,3308 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "dixstruct.h" +#include "../../fb/fb.h" + +#include "Agent.h" +#include "Display.h" +#include "Screen.h" +#include "Trap.h" +#include "Image.h" +#include "Drawable.h" +#include "Client.h" +#include "Visual.h" +#include "Events.h" +#include "GCs.h" +#include "Utils.h" +#include "Handlers.h" +#include "Pixels.h" +#include "Reconnect.h" +#include "GCOps.h" + +#include "compext/Compext.h" + +#include "mibstorest.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +/* + * The list of rectangles composing a region + * s returned by nxagentGetOptimizedRegion- + * Boxes() instead of RegionRects(). + */ + +#define USE_OPTIMIZED_BOXES + +/* + * The rectangles composing a region are de- + * fragmented to reduce the number of synch- + * ronizing PutImage's. + */ + +#define ADVANCED_BOXES_DEFRAG + +/* + * If defined, send the XClearArea at the end + * of the loop synchronizing the shadow pixmap. + * In this way, large images can be splitted but + * the user will see more updates togheter. + */ + +#undef COLLECTED_UPDATES + +#ifdef ADVANCED_BOXES_DEFRAG +#define INCLUDE_MARGIN 10 +#endif + +struct nxagentExposeBackground +{ + PixmapPtr pBackground; + RegionPtr pExpose; +}; + +RESTYPE RT_NX_CORR_BACKGROUND; +RESTYPE RT_NX_CORR_WINDOW; +RESTYPE RT_NX_CORR_PIXMAP; + +int nxagentCorruptedPixmaps = 0; +int nxagentCorruptedWindows = 0; +int nxagentCorruptedBackgrounds = 0; + +int nxagentForceSynchronization = 0; + +_nxagentSynchronizationRec nxagentSynchronization = { (DrawablePtr) NULL, 0, 0, 0, 0, 0 }; + +RegionPtr nxagentDeferredBackgroundExposures = NullRegion; + +/* + * Predicate functions used to synchronize the + * content of the remote drawable with the data + * stored in the virtual frame-buffer. + */ + +void nxagentSynchronizeDrawablePredicate(void *p0, XID x1, void *p2); +void nxagentExposeBackgroundPredicate(void *p0, XID x1, void *p2); + +/* + * Imported from NXresource.c + */ + +extern int nxagentFindClientResource(int, RESTYPE, void *); + +unsigned long nxagentGetColor(DrawablePtr pDrawable, int xPixel, int yPixel); +unsigned long nxagentGetDrawableColor(DrawablePtr pDrawable); +unsigned long nxagentGetRegionColor(DrawablePtr pDrawable, RegionPtr pRegion); + +int nxagentSkipImage = 0; + +static int nxagentTooManyImageData(void) +{ + unsigned int r; + unsigned int limit; + + limit = nxagentOption(ImageRateLimit); + + r = nxagentGetDataRate() / 1000; + + #ifdef TEST + if (r > limit) + { + fprintf(stderr, "Warning: Current bit rate is: %u kB/s.\n", r); + } + #endif + + return (r > limit); +} + +int nxagentSynchronizeDrawable(DrawablePtr pDrawable, int wait, unsigned int breakMask, WindowPtr owner) +{ + int result; + + pDrawable = nxagentSplitDrawable(pDrawable); + + if (nxagentLosslessTrap == 0) + { + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawable: Drawable [%s][%p] with id [%ld] already " + "synchronized.\n", nxagentDrawableType(pDrawable), + (void *) pDrawable, pDrawable -> id); + #endif + + return 0; + } + } + + /* + * What we want here is to avoid drawing on the + * framebuffer and just perform the operation + * on the real X server. This is the purpose of + * the FB trap. At the same time we also want + * to avoid a split, so that the image will be + * transferred in a single operation. + */ + + nxagentFBTrap = 1; + + nxagentSplitTrap = 1; + + result = nxagentSynchronizeDrawableData(pDrawable, breakMask, owner); + + nxagentSplitTrap = 0; + + nxagentFBTrap = 0; + + if (wait == DO_WAIT && nxagentSplitResource(pDrawable) != NULL) + { + nxagentWaitDrawable(pDrawable); + } + + #ifdef TEST + + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + fprintf(stderr, "nxagentSynchronizeDrawable: Drawable %s [%p] with id [%ld] now synchronized.\n", + nxagentDrawableType(pDrawable), (void *) pDrawable, pDrawable -> id); + } + else + { + fprintf(stderr, "nxagentSynchronizeDrawable: Drawable %s [%p] with id [%ld] not fully synchronized.\n", + nxagentDrawableType(pDrawable), (void *) pDrawable, pDrawable -> id); + } + + #endif + + return result; +} + +int nxagentSynchronizeDrawableData(DrawablePtr pDrawable, unsigned int breakMask, WindowPtr owner) +{ + int width, height, depth, length; + unsigned int leftPad, format; + + char *data = NULL; + DrawablePtr pSrcDrawable; + GCPtr pGC; + + int success; + + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + leftPad = 0; + + width = pDrawable -> width; + height = pDrawable -> height; + depth = pDrawable -> depth; + + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawableData: Synchronizing drawable (%s) with geometry [%d][%d][%d].\n", + nxagentDrawableType(pDrawable), width, height, depth); + #endif + + format = (depth == 1) ? XYPixmap : ZPixmap; + + length = nxagentImageLength(width, height, format, leftPad, depth); + + if ((data = malloc(length)) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentSynchronizeDrawableData: WARNING! Failed to allocate memory for the operation.\n"); + #endif + + success = 0; + + goto nxagentSynchronizeDrawableDataEnd; + } + + pSrcDrawable = (pDrawable -> type == DRAWABLE_PIXMAP ? + ((DrawablePtr) nxagentVirtualPixmap((PixmapPtr) pDrawable)) : + pDrawable); + + /* + * Synchronize the whole pixmap if we need + * to download a fresh copy with lossless + * compression turned off. + */ + + if (nxagentLosslessTrap == 1) + { + pGC = nxagentGetGraphicContext(pDrawable); + + if (pGC == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentSynchronizeDrawableData: WARNING! Failed to get the temporary GC.\n"); + #endif + + success = 0; + + goto nxagentSynchronizeDrawableDataFree; + } + + ValidateGC(pDrawable, pGC); + + fbGetImage(pSrcDrawable, 0, 0, + width, height, format, AllPlanes, data); + + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawableData: Forcing synchronization of " + "pixmap at [%p] with lossless compression.\n", (void *) pDrawable); + #endif + + nxagentPutImage(pDrawable, pGC, depth, 0, 0, + width, height, leftPad, format, data); + + success = 1; + + goto nxagentSynchronizeDrawableDataFree; + } + else if (nxagentReconnectTrap == 1) + { + /* + * The pixmap data is not synchronized unless + * we need it. We noticed we have to reconnect + * the pixmaps used by the GC's clip mask. + * The other data will be synchronized on demand. + */ + + if (pDrawable -> depth == 1) + { + #ifdef TEST + + if (nxagentReconnectTrap == 1) + { + static int totalLength; + static int totalReconnectedPixmaps; + + totalLength += length; + totalReconnectedPixmaps++; + + fprintf(stderr, "nxagentSynchronizeDrawableData: Reconnecting pixmap at [%p] [%dx%d] " + "Depth [%d] Size [%d]. Total size [%d]. Total reconnected pixmaps [%d].\n", + (void *) pDrawable, width, height, depth, length, + totalLength, totalReconnectedPixmaps); + } + + #endif + + pGC = nxagentGetGraphicContext(pDrawable); + + if (pGC == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentSynchronizeDrawableData: WARNING! Failed to create the temporary GC.\n"); + #endif + + success = 0; + + goto nxagentSynchronizeDrawableDataFree; + } + + ValidateGC(pDrawable, pGC); + + fbGetImage(pSrcDrawable, 0, 0, + width, height, format, AllPlanes, data); + + nxagentPutImage(pDrawable, pGC, depth, 0, 0, + width, height, leftPad, format, data); + + success = 1; + + goto nxagentSynchronizeDrawableDataFree; + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawableData: Skipping synchronization of " + "pixmap at [%p][%p] during reconnection.\n", (void *) pDrawable, (void*) nxagentVirtualPixmap((PixmapPtr)pDrawable)); + #endif + + nxagentMarkCorruptedRegion(pDrawable, NullRegion); + + success = 1; + + goto nxagentSynchronizeDrawableDataFree; + } + } + } + + /* + * By calling this function with the NullRegion + * as parameter we are requesting to synchro- + * nize the full visible corrupted region of + * the drawable. + */ + + success = nxagentSynchronizeRegion(pDrawable, NullRegion, breakMask, owner); + +nxagentSynchronizeDrawableDataFree: + + if (data != NULL) + { + free(data); + } + +nxagentSynchronizeDrawableDataEnd: + + return success; +} + +/* + * If pRegion is NullRegion, all the viewable + * corrupted region will be synchronized. + */ + +int nxagentSynchronizeRegion(DrawablePtr pDrawable, RegionPtr pRegion, unsigned int breakMask, WindowPtr owner) +{ + GCPtr pGC; + DrawablePtr pSrcDrawable; + BoxPtr pBox; + RegionPtr clipRegion; + + RegionRec tileRegion; + RegionRec exposeRegion; + BoxRec box; + BoxRec tileBox; + + #ifdef COLLECTED_UPDATES + RegionRec collectedUpdates; + #endif + + char *data; + + int nBox; + int x, y; + int w, h; + int extentWidth, extentHeight; + int tileWidth, tileHeight; + int length, format, leftPad; + int i; + int saveTrap; + int success; + int useStoredBitmap; + + unsigned long now; + unsigned long elapsedTime; + + + leftPad = 0; + success = 0; + data = NULL; + pGC = NULL; + clipRegion = NullRegion; + + #ifdef COLLECTED_UPDATES + RegionInit(&collectedUpdates, NullBox, 1); + #endif + + RegionInit(&exposeRegion, NullBox, 1); + + if (nxagentDrawableBitmap(pDrawable) != NullPixmap && + nxagentDrawableStatus((DrawablePtr) nxagentDrawableBitmap(pDrawable)) == Synchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Drawable [%s] at [%p] has an already synchronized " + "bitmap at [%p].\n", nxagentDrawableType(pDrawable), + (void *) pDrawable, (void *) nxagentDrawableBitmap(pDrawable)); + #endif + + nxagentDestroyDrawableBitmap(pDrawable); + } + + /* + * The stored bitmap may be used if we + * are going to synchronize the full + * drawable. + */ + + useStoredBitmap = (nxagentDrawableBitmap(pDrawable) != NullPixmap && pRegion == NullRegion); + + if (useStoredBitmap != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Drawable [%s] at [%p] has a synchronization bitmap at [%p] " + "[%d,%d,%d,%d] with [%ld] rects.\n", nxagentDrawableType(pDrawable), + (void *) pDrawable, (void *) nxagentDrawableBitmap(pDrawable), + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x1, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y1, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x2, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y2, + RegionNumRects(nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)))); + #endif + + clipRegion = nxagentCreateRegion(pDrawable, NULL, 0, 0, pDrawable -> width, pDrawable -> height); + + /* + * Intersecting the viewable region of the + * drawable with the region remaining from + * a previous loop. + */ + + RegionIntersect(clipRegion, clipRegion, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable))); + + /* + * The bitmap regions used in the synchro- + * nizations are only those corrupted also + * on the drawable. In this way, if we put + * a tile in a bad position (e.g. if the + * corrupted region moves), the next synch- + * ronization will fix the error. + */ + + RegionIntersect(clipRegion, clipRegion, + nxagentCorruptedRegion(pDrawable)); + + /* + * The bitmap to synchronize is clipped. + */ + + if (RegionNil(clipRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: The bitmap region [%d,%d,%d,%d] is not viewable. " + "Destroying it.\n", clipRegion -> extents.x1, clipRegion -> extents.y1, + clipRegion -> extents.x2, clipRegion -> extents.y2); + #endif + + nxagentDestroyDrawableBitmap(pDrawable); + + goto nxagentSynchronizeRegionFree; + } + + /* + * Using the saved bitmap as source, instead + * of the drawable itself. + */ + + pSrcDrawable = ((DrawablePtr) nxagentVirtualPixmap(nxagentDrawableBitmap(pDrawable))); + } + else + { + if (pRegion != NullRegion && RegionNil(pRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Region [%d,%d,%d,%d] is nil. Skipping synchronization.\n", + pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2); + #endif + + goto nxagentSynchronizeRegionFree; + } + + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: The [%s] at [%p] is already synchronized.\n", + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + goto nxagentSynchronizeRegionFree; + } + + /* + * Creating a region containing the viewable + * area of drawable. + */ + + clipRegion = nxagentCreateRegion(pDrawable, NULL, 0, 0, pDrawable -> width, pDrawable -> height); + + /* + * If the corrupted region is not viewable, we + * can skip the synchronization. + */ + + RegionIntersect(clipRegion, clipRegion, nxagentCorruptedRegion(pDrawable)); + + if (RegionNil(clipRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: The corrupted region [%d,%d,%d,%d] is not viewable " + "on [%s] at [%p]. Skipping the synchronization.\n", clipRegion -> extents.x1, + clipRegion -> extents.y1, clipRegion -> extents.x2, clipRegion -> extents.y2, + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + goto nxagentSynchronizeRegionFree; + } + + /* + * We can skip the synchronization if the re- + * quested region is not corrupted. Specifying + * a NullRegion as parameter, all the viewable + * corrupted region will be synchronized. + */ + + if (pRegion != NullRegion) + { + RegionIntersect(clipRegion, clipRegion, pRegion); + + if (RegionNil(clipRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Region requested [%d,%d,%d,%d] already " + "synchronized on [%s] at [%p].\n", pRegion -> extents.x1, + pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2, + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + goto nxagentSynchronizeRegionFree; + } + } + + pSrcDrawable = (pDrawable -> type == DRAWABLE_PIXMAP ? + ((DrawablePtr) nxagentVirtualPixmap((PixmapPtr) pDrawable)) : + pDrawable); + } + + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Synchronizing region with coordinates [%d,%d,%d,%d] " + "on [%s] at [%p].\n", clipRegion -> extents.x1, clipRegion -> extents.y1, + clipRegion -> extents.x2, clipRegion -> extents.y2, + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + saveTrap = nxagentGCTrap; + + nxagentGCTrap = 0; + + nxagentFBTrap = 1; + + nxagentSplitTrap = 1; + + pGC = nxagentGetGraphicContext(pDrawable); + + if (pGC == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Failed to create the temporary GC.\n"); + #endif + + goto nxagentSynchronizeRegionFree; + } + + ValidateGC(pDrawable, pGC); + + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Going to synchronize [%ld] rects of [%s] at [%p].\n", + RegionNumRects(clipRegion), nxagentDrawableType(pDrawable), (void *) pDrawable); + + fprintf(stderr, "nxagentSynchronizeRegion: Extents geometry [%d,%d,%d,%d].\n", + clipRegion -> extents.x1, clipRegion -> extents.y1, clipRegion -> extents.x2, clipRegion -> extents.y2); + + fprintf(stderr, "nxagentSynchronizeRegion: Drawable geometry [%d,%d,%d,%d].\n", + pDrawable -> x, pDrawable -> y, pDrawable -> width, pDrawable -> height); + #endif + + /* + * We are going to synchronize the corrupted + * area, so we use the corrupted extents as + * maximum size of the image data. It's im- + * portant to avoid using the drawable size, + * because in case of a huge window it had to + * result in a failed data memory allocation. + */ + + extentWidth = clipRegion -> extents.x2 - clipRegion -> extents.x1; + extentHeight = clipRegion -> extents.y2 - clipRegion -> extents.y1; + + w = tileWidth = (nxagentOption(TileWidth) > extentWidth ? extentWidth : nxagentOption(TileWidth)); + h = tileHeight = (nxagentOption(TileHeight) > extentHeight ? extentHeight : nxagentOption(TileHeight)); + + #ifdef DEBUG + fprintf(stderr, "nxagentSynchronizeRegion: Using tiles of size [%dx%d].\n", tileWidth, tileHeight); + #endif + + data = nxagentAllocateImageData(w, h, pDrawable -> depth, &length, &format); + + if (data == NULL) + { + #ifdef WARNING + + fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Failed to allocate memory for synchronization.\n"); + + /* + * Print detailed informations if the + * image length is zero. + */ + + if (length == 0) + { + fprintf(stderr, "nxagentSynchronizeRegion: Drawable [%s] at [%p] with region geometry [%d][%d,%d,%d,%d].\n", + nxagentDrawableType(pDrawable), (void *) pDrawable, RegionNumRects(clipRegion), + clipRegion -> extents.x1, clipRegion -> extents.y1, + clipRegion -> extents.x2, clipRegion -> extents.y2); + } + + #endif + + goto nxagentSynchronizeRegionFree; + } + + #ifndef USE_OPTIMIZED_BOXES + + pBox = RegionRects(clipRegion); + + #else + + pBox = nxagentGetOptimizedRegionBoxes(clipRegion); + + #endif /* USE_OPTIMIZED_BOXES */ + + nBox = RegionNumRects(clipRegion); + + now = GetTimeInMillis(); + + nxagentSynchronization.abort = 0; + + /* + * Going to split the updated region into small blocks. + */ + + for (i = 0; i < nBox; i++) + { + #ifdef USE_OPTIMIZED_BOXES + + if (pBox[i].x1 == 0 && pBox[i].y1 == 0 && + pBox[i].x2 == 0 && pBox[i].y2 == 0) + { + continue; + } + + #endif + + box = pBox[i]; + + for (y = box.y1; y < box.y2; y += h) + { + h = MIN(box.y2 - y, tileHeight); + + for (x = box.x1; x < box.x2; x += w) + { + w = MIN(box.x2 - x, tileWidth); + + /* + * FIXME: This should not occur. + */ + + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + #ifdef WARNING + + if (pDrawable -> type == DRAWABLE_WINDOW && pSrcDrawable != pDrawable) + { + fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Trying to synchronize " + "the clean drawable type [%d] at [%p] with source at [%p].\n", + pDrawable -> type, (void *) pDrawable, (void *) pSrcDrawable); + } + + #endif + + goto nxagentSynchronizeRegionStop; + } + + if (canBreakOnTimeout(breakMask)) + { + /* + * Abort the synchronization loop if it + * lasts for more than DeferTimeout + * milliseconds. + */ + + elapsedTime = GetTimeInMillis() - now; + + if (elapsedTime > nxagentOption(DeferTimeout)) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Synchronization break with " + "[%lu] ms elapsed.\n", elapsedTime); + #endif + + nxagentSynchronization.abort = 1; + + goto nxagentSynchronizeRegionStop; + } + } + + /* + * Abort the loop if we go out of bandwidth. + */ + + if (breakOnCongestionDrawable(breakMask, pDrawable) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Synchronization break with " + "congestion [%d] blocking [%d].\n", nxagentCongestion, + nxagentBlocking); + #endif + + nxagentSynchronization.abort = 1; + + goto nxagentSynchronizeRegionStop; + } + + /* + * Abort the loop if the display blocks. + */ + + if (breakOnBlocking(breakMask) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Synchronization break with " + "blocking [%d] congestion [%d].\n", nxagentBlocking, + nxagentCongestion); + #endif + + nxagentSynchronization.abort = 1; + + goto nxagentSynchronizeRegionStop; + } + + tileBox.x1 = x; + tileBox.y1 = y; + tileBox.x2 = x + w; + tileBox.y2 = y + h; + + #ifdef DEBUG + fprintf(stderr, "nxagentSynchronizeRegion: Going to synchronize tile [%d,%d,%d,%d].\n", + tileBox.x1, tileBox.y1, tileBox.x2, tileBox.y2); + #endif + + nxagentGetImage(pSrcDrawable, x, y, w, h, format, AllPlanes, data); + + /* + * Going to unmark the synchronized + * region. + */ + + RegionInit(&tileRegion, &tileBox, 1); + + RegionUnion(&exposeRegion, &exposeRegion, &tileRegion); + + #ifdef COLLECTED_UPDATES + RegionAppend(&collectedUpdates, &tileRegion); + #endif + + if (useStoredBitmap != 0) + { + /* + * When a bitmap's tile is synchronized, + * we can clear the corresponding region. + * We can't use the nxagentUnmarkCorrupted- + * Region because we have not a resource + * associated to this pixmap. + */ + + RegionSubtract(nxagentPixmapCorruptedRegion(nxagentDrawableBitmap(pDrawable)), + nxagentPixmapCorruptedRegion(nxagentDrawableBitmap(pDrawable)), &tileRegion); + + /* + * The drawable's corrupted region can + * be cleared if the bitmap's tile data + * matches the drawable's content at the + * same position. + */ + + if (nxagentDrawableStatus(pDrawable) == NotSynchronized) + { + char *cmpData; + + int cmpLength, cmpFormat; + + cmpData = nxagentAllocateImageData(w, h, pDrawable -> depth, &cmpLength, &cmpFormat); + + if (cmpData != NULL) + { + nxagentGetImage(pDrawable, x, y, w, h, format, AllPlanes, cmpData); + + if (memcmp(data, cmpData, cmpLength) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Tile [%d,%d,%d,%d] matches drawable's data at same position.\n", + x, y, x + w, y + h); + #endif + + nxagentUnmarkCorruptedRegion(pDrawable, &tileRegion); + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentSynchronizeRegion: Tile [%d,%d,%d,%d] on drawable [%p] doesn't match.\n", + x, y, x + w, y + h, (void *) pDrawable); + } + #endif + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentSynchronizeRegion: WARNING! Failed to allocate memory to compare tiles.\n"); + #endif + } + + if (cmpData != NULL) + { + free(cmpData); + } + } + } + else + { + nxagentUnmarkCorruptedRegion(pDrawable, &tileRegion); + + if (nxagentDrawableBitmap(pDrawable) != NullPixmap) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Going to clean bitmap at [%p] with newer data.\n", + (void *) nxagentDrawableBitmap(pDrawable)); + #endif + + RegionSubtract(nxagentPixmapCorruptedRegion(nxagentDrawableBitmap(pDrawable)), + nxagentPixmapCorruptedRegion(nxagentDrawableBitmap(pDrawable)), &tileRegion); + } + } + + /* + * Realize the image after comparing the + * source data with the bitmap data. + */ + + nxagentRealizeImage(pDrawable, pGC, pDrawable -> depth, + x, y, w, h, leftPad, format, data); + + RegionUninit(&tileRegion); + + #if !defined(COLLECTED_UPDATES) + + if (owner != NULL) + { + if (nxagentOption(Shadow) == 1 && + (nxagentOption(XRatio) != DONT_SCALE || + nxagentOption(YRatio) != DONT_SCALE)) + { + int scaledx; + int scaledy; + int scaledw; + int scaledh; + + scaledx = nxagentScale(x, nxagentOption(XRatio)); + scaledy = nxagentScale(y, nxagentOption(YRatio)); + + scaledw = nxagentScale(x + w, nxagentOption(XRatio)) - scaledx; + scaledh = nxagentScale(y + h, nxagentOption(YRatio)) - scaledy; + + XClearArea(nxagentDisplay, nxagentWindow(owner), scaledx, scaledy, scaledw, scaledh, 0); + } + else + { + XClearArea(nxagentDisplay, nxagentWindow(owner), x, y, w, h, 0); + } + } + + #endif /* #if !defined(COLLECTED_UPDATES) */ + + /* + * Abort the loop on the user's input. + * This is done here to check for events + * read after the flush caused by the + * PutImage. + */ + + nxagentDispatchHandler((ClientPtr) 0, 0, 0); + + if (breakOnEvent(breakMask) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Synchronization break with " + "new input events.\n"); + #endif + + nxagentSynchronization.abort = 1; + + goto nxagentSynchronizeRegionStop; + } + } + } + } + +nxagentSynchronizeRegionStop: + + nxagentSplitTrap = 0; + + nxagentFBTrap = 0; + + nxagentGCTrap = saveTrap; + + success = 1; + + if (nxagentOption(Shadow) == 0) + { + if (nxagentSynchronization.abort == 1) + { + /* + * Storing the pointer to the drawable we + * were synchronizing when the loop aborted. + * It is used in nxagentSynchronizeDrawable- + * Predicate. + */ + + nxagentSynchronization.pDrawable = pDrawable; + nxagentSynchronization.drawableType = pDrawable -> type; + + if (nxagentDrawableBitmap(pDrawable) == NullPixmap) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Going to create the synchronization bitmap.\n"); + #endif + + nxagentCreateDrawableBitmap(pDrawable); + } + } + else + { + if (nxagentDrawableBitmap(pDrawable) != NullPixmap) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeRegion: Synchronization loop finished. Going to destroy synchronization bitmap.\n"); + #endif + + nxagentDestroyDrawableBitmap(pDrawable); + } + } + + if (pDrawable -> type == DRAWABLE_PIXMAP && + nxagentIsCorruptedBackground((PixmapPtr) pDrawable) == 1 && + RegionNil(&exposeRegion) == 0) + { + struct nxagentExposeBackground eb; + + int i; + + eb.pBackground = (PixmapPtr) pDrawable; + eb.pExpose = &exposeRegion; + + for (i = 0; i < MAXCLIENTS; i++) + { + if (clients[i] != NULL) + { + FindClientResourcesByType(clients[i], RT_WINDOW, + nxagentExposeBackgroundPredicate, &eb); + } + } + } + } + #ifdef COLLECTED_UPDATES + else + { + if (owner != NULL) + { + int overlap = 0; + + RegionValidate(&collectedUpdates, &overlap); + + for (i = 0; i < RegionNumRects(&collectedUpdates); i++) + { + x = RegionRects(&collectedUpdates)[i].x1; + y = RegionRects(&collectedUpdates)[i].y1; + w = RegionRects(&collectedUpdates)[i].x2 - RegionRects(&collectedUpdates)[i].x1; + h = RegionRects(&collectedUpdates)[i].y2 - RegionRects(&collectedUpdates)[i].y1; + + if (nxagentOption(Shadow) == 1 && + (nxagentOption(XRatio) != DONT_SCALE || + nxagentOption(YRatio) != DONT_SCALE)) + { + int scaledx; + int scaledy; + int scaledw; + int scaledh; + + scaledx = nxagentScale(x, nxagentOption(XRatio)); + scaledy = nxagentScale(y, nxagentOption(YRatio)); + + scaledw = nxagentScale(x + w, nxagentOption(XRatio)) - scaledx; + scaledh = nxagentScale(y + h, nxagentOption(YRatio)) - scaledy; + + XClearArea(nxagentDisplay, nxagentWindow(owner), scaledx, scaledy, scaledw, scaledh, 0); + } + else + { + XClearArea(nxagentDisplay, nxagentWindow(owner), x, y, w, h, 0); + } + } + } + } + #endif /* #ifdef COLLECTED_UPDATES */ + +nxagentSynchronizeRegionFree: + + if (clipRegion != NullRegion) + { + nxagentFreeRegion(pDrawable, clipRegion); + } + + if (data != NULL) + { + free(data); + } + + RegionUninit(&exposeRegion); + + #ifdef COLLECTED_UPDATES + + RegionUninit(&collectedUpdates); + + #endif /* #ifdef COLLECTED_UPDATES */ + + return success; +} + +void nxagentSynchronizeBox(DrawablePtr pDrawable, BoxPtr pBox, unsigned int breakMask) +{ + RegionPtr pRegion; + + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeBox: The [%s] at [%p] is already synchronized.\n", + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + return; + } + + if (pBox == NullBox) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeBox: Going to synchronize the whole [%s] at [%p].\n", + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + nxagentSynchronizeRegion(pDrawable, NullRegion, breakMask, NULL); + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeBox: Going to create a region from box [%d,%d,%d,%d].\n", + pBox -> x1, pBox -> y1, pBox -> x2, pBox -> y2); + #endif + + pRegion = nxagentCreateRegion(pDrawable, NULL, pBox -> x1, pBox -> y1, + pBox -> x2 - pBox -> x1, pBox -> y2 - pBox -> y1); + + + if (RegionNil(pRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeBox: Resulting region [%d,%d,%d,%d] is nil. Skipping synchronization.\n", + pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2); + #endif + + nxagentFreeRegion(pDrawable, pRegion); + + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeBox: Going to synchronize the region [%d,%d,%d,%d] of " + "[%s] at [%p].\n", pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, + pRegion -> extents.y2, nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + nxagentSynchronizeRegion(pDrawable, pRegion, breakMask, NULL); + + nxagentFreeRegion(pDrawable, pRegion); + } +} + +void nxagentSynchronizeDrawablePredicate(void *p0, XID x1, void *p2) +{ + DrawablePtr pDrawable = (DrawablePtr) p0; + unsigned int *breakMask = (unsigned int *) p2; + + int shouldClearHiddenRegion = 1; + + /* + * The nxagentSynchronization.abort propa- + * gates a break condition across the resour- + * ces loop, in order to block also the sub- + * sequent synchronizations. + */ + + if (nxagentSynchronization.abort == 1 || + nxagentDrawableStatus(pDrawable) == Synchronized) + { + return; + } + + /* + * In order to implement a kind of round-robin + * synchronization, the previous incomplete + * drawable synchronization is saved to jump + * to the next resource available of same type. + */ + + if (nxagentSynchronization.pDrawable != NULL && + pDrawable -> type == nxagentSynchronization.drawableType) + { + if (nxagentSynchronization.pDrawable != pDrawable) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Skipping drawable [%s][%p] while looking " + "for last synchronized drawable [%p].\n", nxagentDrawableType(pDrawable), + (void *) pDrawable, (void *) nxagentSynchronization.pDrawable); + #endif + + return; + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Last synchronized drawable [%p] found. " + "Skipping to the next resource.\n", (void *) nxagentSynchronization.pDrawable); + #endif + + nxagentSynchronization.pDrawable = NULL; + + return; + } + } + + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + /* + * The pixmaps to be synchronized are those + * used as background or used as source of + * any deferred operations for at least 2 + * times. + */ + + if (NXAGENT_SHOULD_SYNCHRONIZE_PIXMAP(pDrawable) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Skipping pixmap at [%p] " + "with usage [%d] background [%d].\n", (void *) pDrawable, + nxagentPixmapUsageCounter((PixmapPtr) pDrawable), + nxagentIsCorruptedBackground((PixmapPtr) pDrawable)); + #endif + + return; + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Synchronizing pixmap at [%p] " + "with usage [%d] background [%d].\n", (void *) pDrawable, + nxagentPixmapUsageCounter((PixmapPtr) pDrawable), + nxagentIsCorruptedBackground((PixmapPtr) pDrawable)); + } + #endif + } + else if (NXAGENT_SHOULD_SYNCHRONIZE_WINDOW(pDrawable) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Skipping not visible window at [%p].\n", + (void *) pDrawable); + #endif + + if (shouldClearHiddenRegion == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Clearing out the not visible window " + "at [%p].\n", (void *) pDrawable); + #endif + + nxagentCleanCorruptedDrawable(pDrawable); + } + + return; + } + + /* + * Postpone the synchronization if we went + * out of bandwidth or if the display blocks. + * The pixmap synchronization is more careful + * with bandwidth usage. + */ + +/* +FIXME: This condition sounds only as a + complication, as the break parameters + are already checked while synchroni- + zing the drawable. + + if (breakOnCongestion(*breakMask) == 1 || + (pDrawable -> type == DRAWABLE_PIXMAP && + *breakMask != NEVER_BREAK && nxagentCongestion > 0)) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: WARNING! Breaking the " + "synchronization with congestion [%d] blocking [%d].\n", + nxagentCongestion, nxagentBlocking); + #endif + + nxagentSynchronization.abort = 1; + + return; + } +*/ + + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Synchronizing drawable [%s][%p] " + "with geometry (%dx%d).\n", nxagentDrawableType(pDrawable), + (void *) pDrawable, pDrawable -> width, pDrawable -> height); + + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Corrupted extents [%d,%d,%d,%d] " + "with [%ld] rects.\n", nxagentCorruptedRegion(pDrawable) -> extents.x1, + nxagentCorruptedRegion(pDrawable) -> extents.y1, nxagentCorruptedRegion(pDrawable) -> + extents.x2, nxagentCorruptedRegion(pDrawable) -> extents.y2, + RegionNumRects(nxagentCorruptedRegion(pDrawable))); + #endif + + /* + * The stored bitmap is destroyed inside + * the synchronization loop, so we have + * to check here its presence to know if + * we can clear the dirty windows. + */ + + shouldClearHiddenRegion = (nxagentDrawableBitmap(pDrawable) == NullPixmap); + + nxagentSynchronizeDrawable(pDrawable, DONT_WAIT, *breakMask, NULL); + + if (nxagentDrawableStatus(pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Drawable [%s][%p] not fully synchronized.\n", + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + /* + * If the remaining corrupted region is on + * an hidden section (not viewable or outside + * of the pixmap's area) of a drawable, + * we can clear it. + */ + + if (nxagentSynchronization.abort == 0 && + shouldClearHiddenRegion == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawablePredicate: Clearing out the remaining corrupted " + "[%s] at [%p].\n", nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + nxagentCleanCorruptedDrawable(pDrawable); + } + } +} + +void nxagentSynchronizationLoop(unsigned int mask) +{ + unsigned int breakMask; + + int doRoundRobin; + +/* +FIXME: All drawables should be set as synchronized and + never marked as corrupted while the display is + down. +*/ + + nxagentSkipImage = nxagentTooManyImageData(); + + if (nxagentOption(ImageRateLimit) && nxagentSkipImage) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeDrawable: Skipping due to bit rate limit reached.\n"); + #endif + + return; + } + + if (NXDisplayError(nxagentDisplay) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizationLoop: WARNING! Not synchronizing the drawables " + "with the display down.\n"); + #endif + + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentSynchronizationLoop: Synchronizing [%d] windows [%d] pixmaps " + "and [%d] backgrounds with mask [%u].\n", nxagentCorruptedWindows, nxagentCorruptedPixmaps, + nxagentCorruptedBackgrounds, mask); + + fprintf(stderr, "nxagentSynchronizationLoop: Stored bitmaps [%d] windows [%d] pixmaps " + "and [%d] backgrounds.\n", nxagentSynchronization.windowBitmaps, + nxagentSynchronization.pixmapBitmaps, nxagentSynchronization.backgroundBitmaps); + + fprintf(stderr, "nxagentSynchronizationLoop: Starting loops with congestion [%d] " + "blocking [%d].\n", nxagentCongestion, nxagentBlocking); + #endif + + breakMask = mask; + + /* + * The resource counter can be reset if we + * have not aborted the synchronization loop, + * if we are not skipping resources to do + * round-robin and if the bitmaps are all + * synchronized. + */ + + doRoundRobin = (nxagentSynchronization.pDrawable != NULL); + + nxagentSynchronization.abort = 0; + + /* + * Synchronize the windows. + */ + + if (NXAGENT_SHOULD_SYNCHRONIZE_CORRUPTED_WINDOWS(mask)) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizationLoop: Going to loop through corrupted window resources.\n"); + #endif + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_CORR_WINDOW, + nxagentSynchronizeDrawablePredicate, &breakMask); + + #ifdef TEST + + if (nxagentSynchronization.abort == 0 && + nxagentSynchronization.windowBitmaps == 0 && + doRoundRobin == 0) + { + if (nxagentCorruptedWindows > 0) + { + fprintf(stderr, "nxagentSynchronizationLoop: Closing the loop with [%d] " + "corrupted windows.\n", nxagentCorruptedWindows); + } + + nxagentCorruptedWindows = 0; + } + + #endif + } + + /* + * Synchronize the backgrounds. + */ + + if (nxagentSynchronization.abort == 0 && + NXAGENT_SHOULD_SYNCHRONIZE_CORRUPTED_BACKGROUNDS(mask)) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizationLoop: Going to loop through corrupted background resources.\n"); + #endif + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_CORR_BACKGROUND, + nxagentSynchronizeDrawablePredicate, &breakMask); + + #ifdef TEST + + if (nxagentSynchronization.abort == 0 && + nxagentSynchronization.backgroundBitmaps == 0 && + doRoundRobin == 0) + { + if (nxagentCorruptedBackgrounds > 0) + { + fprintf(stderr, "nxagentSynchronizationLoop: Closing the loop with [%d] " + "corrupted backgrounds.\n", nxagentCorruptedBackgrounds); + } + + nxagentCorruptedBackgrounds = 0; + } + + #endif + } + + /* + * If there is bandwidth remaining, synchronize + * the pixmaps. Synchronizing a pixmap doesn't + * produce any visible results. Better is to + * synchronize them on demand, before using the + * pixmap in a copy or in a composite operation. + */ + + if (nxagentSynchronization.abort == 0 && + NXAGENT_SHOULD_SYNCHRONIZE_CORRUPTED_PIXMAPS(mask)) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizationLoop: Going to loop through corrupted pixmap resources.\n"); + #endif + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_CORR_PIXMAP, + nxagentSynchronizeDrawablePredicate, &breakMask); + + + if (nxagentSynchronization.abort == 0 && + nxagentSynchronization.pixmapBitmaps == 0 && + doRoundRobin == 0) + { + #ifdef TEST + + if (nxagentCorruptedPixmaps > 0) + { + fprintf(stderr, "nxagentSynchronizationLoop: Closing the loop with [%d] " + "corrupted pixmaps.\n", nxagentCorruptedPixmaps); + } + + #endif + + nxagentCorruptedPixmaps = 0; + } + + } + + /* + * If the last synchronized drawable has been + * removed, we have to reset the variable sto- + * ring its pointer. + */ + + if (nxagentSynchronization.pDrawable != NULL && + nxagentFindClientResource(serverClient -> index, RT_NX_CORR_WINDOW, + nxagentSynchronization.pDrawable) == 0 && + nxagentFindClientResource(serverClient -> index, RT_NX_CORR_BACKGROUND, + nxagentSynchronization.pDrawable) == 0 && + nxagentFindClientResource(serverClient -> index, RT_NX_CORR_PIXMAP, + nxagentSynchronization.pDrawable) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizationLoop: Synchronization drawable [%p] removed from resources.\n", + (void *) nxagentSynchronization.pDrawable); + #endif + + nxagentSynchronization.pDrawable = NULL; + } + + #ifdef TEST + fprintf(stderr, "nxagentSynchronizationLoop: Closing loops with congestion [%d] " + "blocking [%d].\n", nxagentCongestion, nxagentBlocking); + + fprintf(stderr, "nxagentSynchronizationLoop: There are now [%d] windows [%d] pixmaps " + "and [%d] backgrounds to synchronize.\n", nxagentCorruptedWindows, + nxagentCorruptedPixmaps, nxagentCorruptedBackgrounds); + #endif +} + +RegionPtr nxagentCreateRegion(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int width, int height) +{ + RegionPtr pRegion; + BoxRec box; + + box.x1 = x; + box.y1 = y; + box.x2 = x + width; + box.y2 = y + height; + + pRegion = RegionCreate(&box, 1); + + /* + * Clipping the region. + */ + + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + BoxRec tmpBox; + RegionRec tmpRegion; + + /* + * The region created doesn't need to be clipped + * if it has the pixmap dimensions. + */ + + if (x != 0 || y != 0 || + width != pDrawable -> width || + height != pDrawable -> height) + { + tmpBox.x1 = 0; + tmpBox.y1 = 0; + tmpBox.x2 = pDrawable -> width; + tmpBox.y2 = pDrawable -> height; + + RegionInit(&tmpRegion, &tmpBox, 1); + + RegionIntersect(pRegion, &tmpRegion, pRegion); + + RegionUninit(&tmpRegion); + } + } + else + { + /* + * We use the clipList because the borderClip + * contains also parts of the window covered + * by its children. + */ + + RegionTranslate(pRegion, + pDrawable -> x, pDrawable -> y); + + if (nxagentWindowPriv((WindowPtr) pDrawable) -> hasTransparentChildren == 1) + { + RegionIntersect(pRegion, pRegion, &((WindowPtr) pDrawable) -> borderClip); + } + else + { + RegionIntersect(pRegion, pRegion, &((WindowPtr) pDrawable) -> clipList); + } + + RegionTranslate(pRegion, + -pDrawable -> x, -pDrawable -> y); + } + + #ifdef TEST + fprintf(stderr, "nxagentCreateRegion: New region created with coordinates [%d,%d,%d,%d].\n", + pRegion -> extents.x1, pRegion -> extents.y1, + pRegion -> extents.x2, pRegion -> extents.y2); + #endif + + /* + * If the pRegion is NIL we don't need + * to intersect it with the GC's clipmask. + */ + + if (RegionNil(pRegion) == 0 && + pGC != NULL && pGC -> clientClip != NULL && + pGC -> clientClipType == CT_REGION) + { + RegionRec clipRegion; + + RegionInit(&clipRegion, NullBox, 1); + + RegionCopy(&clipRegion, (RegionPtr) pGC -> clientClip); + + /* + * The clip origin is relative to the origin of + * the destination drawable. The clip mask coor- + * dinates are relative to the clip origin. + */ + + if (pGC -> clipOrg.x != 0 || pGC -> clipOrg.y != 0) + { + RegionTranslate(&clipRegion, pGC -> clipOrg.x, pGC -> clipOrg.y); + } + + #ifdef TEST + fprintf(stderr, "nxagentCreateRegion: Clipping region to the clip mask with coordinates [%d,%d,%d,%d].\n", + clipRegion.extents.x1, clipRegion.extents.y1, + clipRegion.extents.x2, clipRegion.extents.y2); + #endif + + RegionIntersect(pRegion, pRegion, &clipRegion); + + RegionUninit(&clipRegion); + } + + return pRegion; +} + +void nxagentMarkCorruptedRegion(DrawablePtr pDrawable, RegionPtr pRegion) +{ + int x; + int y; + int width; + int height; + + if (pRegion != NullRegion && RegionNil(pRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentMarkCorruptedRegion: Region [%d,%d,%d,%d] is nil. Skipping operation.\n", + pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2); + #endif + + return; + } + + /* + * If the drawable was synchronized, the counter + * reporting the number of corrupted drawables + * must be increased. Moreover the corrupted ti- + * mestamp must be set. + */ + + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + if (pDrawable -> type == DRAWABLE_WINDOW) + { + nxagentAllocateCorruptedResource(pDrawable, RT_NX_CORR_WINDOW); + } + + nxagentSetCorruptedTimestamp(pDrawable); + } + + if (pRegion == NullRegion) + { + x = 0; + y = 0; + + width = pDrawable -> width; + height = pDrawable -> height; + + #ifdef TEST + fprintf(stderr, "nxagentMarkCorruptedRegion: Fully invalidating %s [%p] with " + "coordinates [%d,%d][%d,%d].\n", nxagentDrawableType(pDrawable), + (void *) pDrawable, x, y, width, height); + #endif + + pRegion = nxagentCreateRegion(pDrawable, NULL, x, y, width, height); + + nxagentValidateSplit(pDrawable, pRegion); + + RegionUnion(nxagentCorruptedRegion(pDrawable), + nxagentCorruptedRegion(pDrawable), pRegion); + + nxagentFreeRegion(pDrawable, pRegion); + } + else + { + #ifdef TEST + + x = pRegion -> extents.x1; + y = pRegion -> extents.y1; + + width = pRegion -> extents.x2 - pRegion -> extents.x1; + height = pRegion -> extents.y2 - pRegion -> extents.y1; + + fprintf(stderr, "nxagentMarkCorruptedRegion: Partly invalidating %s [%p] with " + "coordinates [%d,%d][%d,%d].\n", nxagentDrawableType(pDrawable), + (void *) pDrawable, x, y, width, height); + + #endif + + nxagentValidateSplit(pDrawable, pRegion); + + RegionUnion(nxagentCorruptedRegion(pDrawable), + nxagentCorruptedRegion(pDrawable), pRegion); + } +} + +void nxagentUnmarkCorruptedRegion(DrawablePtr pDrawable, RegionPtr pRegion) +{ + int oldStatus; + + if (pRegion != NullRegion && RegionNil(pRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentUnmarkCorruptedRegion: Region [%d,%d,%d,%d] is nil. Skipping operation.\n", + pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2); + #endif + + return; + } + + oldStatus = nxagentDrawableStatus(pDrawable); + + if (oldStatus == Synchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentUnmarkCorruptedRegion: Drawable %s [%p] already synchronized.\n", + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + return; + } + + if (pRegion == NullRegion) + { + #ifdef TEST + fprintf(stderr, "nxagentUnmarkCorruptedRegion: Fully validating %s [%p].\n", + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + nxagentValidateSplit(pDrawable, NULL); + + RegionEmpty(nxagentCorruptedRegion(pDrawable)); + } + else + { + #ifdef TEST + + fprintf(stderr, "nxagentUnmarkCorruptedRegion: Validating %s [%p] with region [%d,%d,%d,%d].\n", + nxagentDrawableType(pDrawable), (void *) pDrawable, + pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2); + + #endif + + nxagentValidateSplit(pDrawable, pRegion); + + RegionSubtract(nxagentCorruptedRegion(pDrawable), + nxagentCorruptedRegion(pDrawable), pRegion); + } + + /* + * If the drawable becomes synchronized, the + * counter reporting the number of corrupted + * drawables must be decreased. Moreover the + * corrupted timestamp must be reset. + */ + + if (oldStatus == NotSynchronized && + nxagentDrawableStatus(pDrawable) == Synchronized) + { + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentDestroyCorruptedResource(pDrawable, RT_NX_CORR_BACKGROUND); + + nxagentDestroyCorruptedResource(pDrawable, RT_NX_CORR_PIXMAP); + + nxagentPixmapPriv(nxagentRealPixmap((PixmapPtr) pDrawable)) -> containTrapezoids = 0; + } + else + { + nxagentDestroyCorruptedResource(pDrawable, RT_NX_CORR_WINDOW); + } + + nxagentResetCorruptedTimestamp(pDrawable); + + /* + * If the resource is no longer dirty, + * the associated bitmap is destroyed. + */ + + if (nxagentDrawableBitmap(pDrawable) != NullPixmap) + { + nxagentDestroyDrawableBitmap(pDrawable); + } + } +} + +void nxagentMoveCorruptedRegion(WindowPtr pWin, unsigned int mask) +{ + /* + * If a window is resized, its corrupted + * region is moved according to the bit + * gravity. + */ + + if (nxagentDrawableStatus((DrawablePtr) pWin) == NotSynchronized) + { + if (((mask & CWHeight) && nxagentWindowPriv(pWin) -> height != pWin -> drawable.height) || + ((mask & CWWidth) && nxagentWindowPriv(pWin) -> width != pWin -> drawable.width)) + { + int nx, ny; + + GravityTranslate(0, 0, + nxagentWindowPriv(pWin) -> x - pWin -> origin.x + wBorderWidth(pWin), + nxagentWindowPriv(pWin) -> y - pWin -> origin.y + wBorderWidth(pWin), + pWin -> drawable.width - nxagentWindowPriv(pWin) -> width, + pWin -> drawable.height - nxagentWindowPriv(pWin) -> height, + pWin -> bitGravity, &nx, &ny); + + #ifdef TEST + fprintf(stderr, "nxagentMoveCorruptedRegion: Moving the corrupted region to [%d,%d] for window [%p].\n", + nx, ny, (void *) pWin); + #endif + + RegionTranslate(nxagentCorruptedRegion((DrawablePtr) pWin), + nx, ny); + + /* + * Having moved the corrupted region, we + * need to invalidate the pending commits + * or otherwise the image will fall in + * the wrong area. + */ + + nxagentValidateSplit((DrawablePtr) pWin, NULL); + + + /* + * The window reconfiguration invalidates + * the synchronization bitmap. + */ + + nxagentDestroyDrawableBitmap((DrawablePtr) pWin); + } + } +} + +/* + * The DDX layer uses an 'Y-X banding' representation of + * regions: it sorts all rectangles composing a region + * using first the y-dimension, than the x-dimension; mo- + * reover it organizes the rectangles in 'bands' sharing + * the same y-dimension. This representation does not mi- + * nimize the number of rectangles. For example, the fol- + * lowing region has 4 rectangles: + * + * +-----------+ + * | | +---+ + * | A | | B | + * | | +---+ + * +-----------+ + * + * The rectangle 'B' creates a band which splits the rec- + * tangle A in 3 parts, for a total of 3 bands. The num- + * ber of rectangles composing the region is 4. + * + * This kind of representation is not advisable for the + * lazy synchronization because, in the example above, + * the nxagent had to send 4 put images instead of 2. + * + * To minimize the problem we use the following function: + * by traversing the list of rectangles we merge all bo- + * xes with same x coordinates and coincident y, in order + * to create an X-Y banding. + * + * Be careful: all the coordinates of boxes merged are + * set to 0, so take care of this when looping through + * the box list returned by this function. + */ + +BoxPtr nxagentGetOptimizedRegionBoxes(RegionPtr pRegion) +{ + BoxPtr pBox; + + BoxRec boxExtents; + + int nBox; + int i, j; + + #ifdef DEBUG + int nBoxOptim; + #endif + + pBox = RegionRects(pRegion); + + nBox = RegionNumRects(pRegion); + + #ifdef TEST + fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Going to optimize region at [%p] with [%d] rects.\n", + (void *) pRegion, nBox); + #endif + + if (nBox <= 1) + { + return pBox; + } + + #ifdef DEBUG + nBoxOptim = nBox; + #endif + + /* + * The boxes are now grouped to grown as much + * as possible, using their overlapping vertex + * as rule. + */ + + for (i = 0; i < nBox; i++) + { + /* + * If the coordinates are (0,0) the box + * has been already merged, so we can skip + * it. + */ + + if (pBox[i].x1 == 0 && pBox[i].y1 == 0 && + pBox[i].x2 == 0 && pBox[i].y2 == 0) + { + continue; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Referential box [%d] has coordinates [%d,%d,%d,%d].\n", + i, pBox[i].x1, pBox[i].y1, pBox[i].x2, pBox[i].y2); + #endif + + #ifdef ADVANCED_BOXES_DEFRAG + + boxExtents.x1 = pBox[i].x1; + boxExtents.y1 = pBox[i].y1; + boxExtents.x2 = pBox[i].x2; + + #endif + + boxExtents.y2 = pBox[i].y2; + + for (j = i+1; j < nBox; j++) + { + if (pBox[j].x1 == 0 && pBox[j].y1 == 0 && + pBox[j].x2 == 0 && pBox[j].y2 == 0) + { + continue; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Mergeable box [%d] has coordinates [%d,%d,%d,%d].\n", + j, pBox[j].x1, pBox[j].y1, pBox[j].x2, pBox[j].y2); + #endif + + /* + * Each consequent box is merged if its + * higher side overlaps the lower side + * of current box. + * In case of ADVANCED_BOXES_DEFRAG the higher + * side must be included within a range + * defined by INCLUDE_MARGIN. + */ + + #ifndef ADVANCED_BOXES_DEFRAG + + if (pBox[j].y1 == boxExtents.y2 && + pBox[j].x1 == pBox[i].x1 && + pBox[j].x2 == pBox[i].x2) + + #else + + if (pBox[j].x1 > boxExtents.x1 - INCLUDE_MARGIN && + pBox[j].x1 < boxExtents.x1 + INCLUDE_MARGIN && + pBox[j].y1 > boxExtents.y2 - INCLUDE_MARGIN && + pBox[j].y1 < boxExtents.y2 + INCLUDE_MARGIN && + pBox[j].x2 > boxExtents.x2 - INCLUDE_MARGIN && + pBox[j].x2 < boxExtents.x2 + INCLUDE_MARGIN) + + #endif + { + #ifdef DEBUG + fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Going to merge box at [%d] with box at [%d].\n", + j, i); + #endif + + #ifdef ADVANCED_BOXES_DEFRAG + + if (pBox[j].x1 < boxExtents.x1) + { + boxExtents.x1 = pBox[j].x1; + } + + if (pBox[j].x2 > boxExtents.x2) + { + boxExtents.x2 = pBox[j].x2; + } + + if (pBox[j].y1 < boxExtents.y1) + { + boxExtents.y1 = pBox[j].y1; + } + + #endif + + if (pBox[j].y2 > boxExtents.y2) + { + boxExtents.y2 = pBox[j].y2; + } + + /* + * By appending a box to another, we have + * to remove it from the box list. We do + * this by setting its coordinates to (0,0) + * and by checking their value in the main + * loop. + */ + + pBox[j].x1 = pBox[j].y1 = pBox[j].x2 = pBox[j].y2 = 0; + + #ifdef DEBUG + nBoxOptim--; + #endif + } + } + + /* + * Extend the box height. + */ + + #ifdef ADVANCED_BOXES_DEFRAG + + pBox[i].x1 = boxExtents.x1; + pBox[i].y1 = boxExtents.y1; + pBox[i].x2 = boxExtents.x2; + + #endif + + pBox[i].y2 = boxExtents.y2; + } + + #ifdef ADVANCED_BOXES_DEFRAG + + /* + * The new list need to be validated to + * avoid boxes overlapping. This code may + * be improved to remove also the partial- + * ly overlapping boxes. + */ + + for (i = 0; i < nBox; i++) + { + if (pBox[i].x1 == 0 && pBox[i].y1 == 0 && + pBox[i].x2 == 0 && pBox[i].y2 == 0) + { + continue; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Referential box [%d] has coordinates [%d,%d,%d,%d].\n", + i, pBox[i].x1, pBox[i].y1, pBox[i].x2, pBox[i].y2); + #endif + + boxExtents.x1 = pBox[i].x1; + boxExtents.y1 = pBox[i].y1; + boxExtents.x2 = pBox[i].x2; + boxExtents.y2 = pBox[i].y2; + + for (j = i+1; j < nBox; j++) + { + if (pBox[j].x1 == 0 && pBox[j].y1 == 0 && + pBox[j].x2 == 0 && pBox[j].y2 == 0) + { + continue; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Mergeable box [%d] has coordinates [%d,%d,%d,%d].\n", + j, pBox[j].x1, pBox[j].y1, pBox[j].x2, pBox[j].y2); + #endif + + if ((boxExtents.x1 <= pBox[j].x1 && + boxExtents.x2 >= pBox[j].x2 && + boxExtents.y1 <= pBox[j].y1 && + boxExtents.y2 >= pBox[j].y2)) + { + /* + * If a box is completely inside + * another, we set its coordinates + * to 0 to consider it as merged. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Going to merge box [%d,%d,%d,%d] " + "with its box container [%d,%d,%d,%d].\n", pBox[j].x1, pBox[j].y1, + pBox[j].x2, pBox[j].y2, boxExtents.x1, boxExtents.y1, boxExtents.y1, + boxExtents.y2); + #endif + + pBox[j].x1 = pBox[j].y1 = pBox[j].x2 = pBox[j].y2 = 0; + + #ifdef DEBUG + nBoxOptim--; + #endif + } + } + } + + #endif + + #ifdef DEBUG + fprintf(stderr, "nxagentGetOptimizedRegionBoxes: Original boxes number [%d] Optimized boxes number [%d].\n", + nBox, nBoxOptim); + #endif + + return pBox; +} + +unsigned long nxagentGetColor(DrawablePtr pDrawable, int xPixel, int yPixel) +{ + XImage *ximage; + Visual *pVisual; + char *data; + + int depth, format, length; + int leftPad = 0; + unsigned long pixel; + + depth = pDrawable -> depth; + format = (depth == 1) ? XYPixmap : ZPixmap; + length = nxagentImageLength(1, 1, format, leftPad, depth); + + if ((data = malloc(length)) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentGetColor: WARNING! Failed to allocate memory for the operation.\n"); + #endif + + return -1; + } + + pVisual = nxagentImageVisual(pDrawable, depth); + + if (pVisual == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentGetColor: WARNING! Visual not found. Using default visual.\n"); + #endif + + pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual; + } + + fbGetImage(pDrawable, xPixel, yPixel, 1, 1, format, AllPlanes, data); + + ximage = XCreateImage(nxagentDisplay, pVisual, depth, format, leftPad, (char *) data, + 1, 1, BitmapPad(nxagentDisplay), + nxagentImagePad(1, format, leftPad, 1)); + + if (ximage == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentGetColor: WARNING! Failed to create the XImage.\n"); + #endif + + free(data); + + return -1; + } + + pixel = XGetPixel(ximage, 0, 0); + + XDestroyImage(ximage); + + return pixel; +} + +/* + * This function could be used to determine + * the ClearArea color of corrupted regions + * on screen. + */ + +unsigned long nxagentGetRegionColor(DrawablePtr pDrawable, RegionPtr pRegion) +{ + int xPicker, yPicker; + + if (RegionNil(pRegion) == 1) + { + return nxagentGetDrawableColor(pDrawable); + } + + /* + * The pixel used as reference is the first + * outer pixel at the bottom right corner + * of corrupted region extents. + */ + + xPicker = pRegion -> extents.x2 + 1; + + if (xPicker > pDrawable -> width) + { + xPicker = pDrawable -> width; + } + + yPicker = pRegion -> extents.y2 + 1; + + if (yPicker > pDrawable -> height) + { + yPicker = pDrawable -> height; + } + + return nxagentGetColor(pDrawable, xPicker, yPicker); +} + +unsigned long nxagentGetDrawableColor(DrawablePtr pDrawable) +{ + int xPicker, yPicker; + + /* + * The pixel used to determine the co- + * lor of a drawable is at coordinates + * (x + width - 4, y + 4). + */ + + xPicker = pDrawable -> width - 4; + + yPicker = 4; + + return nxagentGetColor(pDrawable, xPicker, yPicker); +} + +void nxagentClearRegion(DrawablePtr pDrawable, RegionPtr pRegion) +{ + WindowPtr pWin; + BoxPtr pBox; + + unsigned long color; + unsigned long backupPixel = 0; + int nBox, i; + int restore; + + #ifdef DEBUG + static int nBoxCleared; + #endif + + if (pDrawable -> type != DRAWABLE_WINDOW) + { + #ifdef TEST + fprintf(stderr, "nxagentClearRegion: Cannot clear a pixmap. Exiting.\n"); + #endif + + return; + } + + if (pRegion == NullRegion || RegionNil(pRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentClearRegion: The region is empty. Exiting.\n"); + #endif + + return; + } + + pWin = (WindowPtr) pDrawable; + + restore = 0; + + /* + * If the window has already a background, we + * can hope it will be nice. + */ + + if (pWin -> backgroundState != None) + { + #ifdef DEBUG + fprintf(stderr, "nxagentClearRegion: Window at [%p] has background state [%u].\n", + (void *) pWin, pWin -> backgroundState); + #endif + } + else + { + /* + * Save the original state. + */ + + backupPixel = pWin -> background.pixel; + + color = nxagentGetDrawableColor((DrawablePtr) pWin); + + if (color == -1) + { + color = 0xffffff; + } + + pWin -> backgroundState = BackgroundPixel; + pWin -> background.pixel = color; + + nxagentChangeWindowAttributes(pWin, CWBackPixel); + + #ifdef DEBUG + fprintf(stderr, "nxagentClearRegion: Window at [%p] now has pixel background [%ld].\n", + (void *) pWin, color); + #endif + + restore = 1; + } + + pBox = nxagentGetOptimizedRegionBoxes(pRegion); + + nBox = RegionNumRects(pRegion); + + for (i = 0; i < nBox; i++) + { + if (pBox[i].x1 == 0 && pBox[i].y1 == 0 && + pBox[i].x2 == 0 && pBox[i].y2 == 0) + { + continue; + } + + XClearArea(nxagentDisplay, nxagentWindow(pWin), pBox[i].x1, pBox[i].y1, + pBox[i].x2 - pBox[i].x1, pBox[i].y2 - pBox[i].y1, False); + + #ifdef DEBUG + nBoxCleared++; + #endif + } + + /* + * Restore the old state. + */ + + if (restore == 1) + { + pWin -> backgroundState = None; + pWin -> background.pixel = backupPixel; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentClearRegion: Number of cleared boxes is [%d].\n", nBoxCleared); + #endif +} + +void nxagentFillRemoteRegion(DrawablePtr pDrawable, RegionPtr pRegion) +{ + GCPtr pGC; + BoxPtr pBox; + XRectangle *pRects; + + int nrects; + int i; + + if (RegionNil(pRegion) == 1) + { + return; + } + + pGC = nxagentGetGraphicContext(pDrawable); + + nrects = RegionNumRects(pRegion); + + #ifdef TEST + fprintf(stderr, "nxagentFillRemoteRegion: Going to fill remote region [%d,%d,%d,%d] rects [%d] with color [%lu].\n", + pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2, + nrects, pGC -> fgPixel); + #endif + + if (nrects == 1) + { + XFillRectangle(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + pRegion -> extents.x1, pRegion -> extents.y1, + pRegion -> extents.x2 - pRegion -> extents.x1, + pRegion -> extents.y2 - pRegion -> extents.y1); + } + else + { + pBox = RegionRects(pRegion); + + pRects = malloc(nrects * sizeof(XRectangle)); + + for (i = 0; i < nrects; i++) + { + pRects[i].x = pBox[i].x1; + pRects[i].y = pBox[i].y1; + pRects[i].width = pBox[i].x2 - pBox[i].x1; + pRects[i].height = pBox[i].y2 - pBox[i].y1; + } + + XFillRectangles(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + pRects, nrects); + + free(pRects); + } +} + +int nxagentDestroyCorruptedWindowResource(void * p, XID id) +{ + #ifdef TEST + fprintf(stderr, "nxagentDestroyCorruptedWindowResource: Removing corrupted window [%p] from resources.\n", + (void *) p); + #endif + + nxagentWindowPriv((WindowPtr) p) -> corruptedId = None; + + return 1; +} + +int nxagentDestroyCorruptedPixmapResource(void * p, XID id) +{ + #ifdef TEST + fprintf(stderr, "nxagentDestroyCorruptedPixmapResource: Removing corrupted pixmap [%p] from resources.\n", + (void *) p); + #endif + + nxagentPixmapPriv((PixmapPtr) p) -> corruptedId = None; + + return 1; +} + +int nxagentDestroyCorruptedBackgroundResource(void * p, XID id) +{ + #ifdef TEST + fprintf(stderr, "nxagentDestroyCorruptedBackgroundResource: Removing corrupted pixmap background [%p] from resources.\n", + (void *) p); + #endif + + nxagentPixmapPriv((PixmapPtr) p) -> corruptedBackgroundId = None; + + return 1; +} + +void nxagentPointsToDirtyRegion(DrawablePtr pDrawable, int mode, + int nPoints, xPoint *pPoints) +{ + RegionPtr pRegion; + RegionRec tmpRegion; + BoxRec box, extents; + + xPoint *xp; + int np; + + np = nPoints; + xp = pPoints; + + pRegion = RegionCreate(NullBox, 1); + + while (np--) + { + if (CoordModePrevious) + { + box.x1 = box.x2 = (xp-1) -> x + xp -> x; + box.y1 = box.y2 = (xp-1) -> y + xp -> y; + } + else + { + box.x1 = box.x2 = xp -> x; + box.y1 = box.y2 = xp -> y; + } + + #ifdef TEST + fprintf(stderr, "nxagentPointsToDirtyRegion: Adding the point (%d,%d) to the dirty region.\n", + box.x1, box.y1); + #endif + + /* + * By using REGION_APPEND() and REGION_VALIDATE() + * this loop could become less expensive. + */ + + RegionInit(&tmpRegion, &box, 1); + + RegionUnion(pRegion, pRegion, &tmpRegion); + + RegionUninit(&tmpRegion); + + xp++; + } + + extents = *RegionExtents(pRegion); + + RegionReset(pRegion, &extents); + + #ifdef TEST + fprintf(stderr, "nxagentPointsToDirtyRegion: The resulting dirty region has [%ld] rects and" + " extents (%d,%d,%d,%d).\n", RegionNumRects(pRegion), extents.x1, + extents.y1, extents.x2, extents.y2); + #endif + + nxagentMarkCorruptedRegion(pDrawable, pRegion); + + RegionDestroy(pRegion); +} + +#ifdef DUMP + +#define USE_MULTIPLE_COLORS + +void nxagentCorruptedRegionOnWindow(void *p0, XID x, void *p2) +{ + WindowPtr pWin = (WindowPtr) p0; + RegionPtr clipRegion; + RegionRec visRegion; + BoxPtr pBox; + + XlibGC gc; + XGCValues value; + + static unsigned long color = 0xff000000; + int nrectangles; + int i; + + /* + * There are no regions to draw. + */ + + if (nxagentDrawableStatus((DrawablePtr) pWin) == Synchronized) + { + return; + } + + /* + * The window is not visible. + */ + + if (nxagentWindowIsVisible(pWin) == 0) + { + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentCorruptedRegionOnWindow: Going to draw on window at [%p].\n", + (void *) pWin); + #endif + + clipRegion = nxagentCreateRegion((DrawablePtr) pWin, NULL, 0, 0, + pWin -> drawable.width, pWin -> drawable.height); + + RegionInit(&visRegion, NullBox, 1); + + RegionIntersect(&visRegion, clipRegion, nxagentCorruptedRegion((DrawablePtr) pWin)); + + nxagentFreeRegion(pWin -> drawable.pScreen, clipRegion); + + if (RegionNil(&visRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentCorruptedRegionOnWindow: The corrupted region of window at [%p] is hidden.\n", + (void *) pWin); + #endif + + RegionUninit(&visRegion); + + return; + } + + nxagentClearRegion((DrawablePtr) pWin, &visRegion); + + #ifdef USE_MULTIPLE_COLORS + + color += nxagentWindow(pWin) * 5; + + if (color == 0 || color == 0xffffffff) + { + color = 0xff000000; + } + + #endif + + value.foreground = color; + value.subwindow_mode = IncludeInferiors; + + gc = XCreateGC(nxagentDisplay, nxagentWindow(pWin), GCForeground | GCSubwindowMode, &value); + + nrectangles = RegionNumRects(&visRegion); + + #ifdef TEST + fprintf(stderr, "nxagentCorruptedRegionOnWindow: Going to draw the region with extents [%d,%d,%d,%d] and [%d] rects.\n", + visRegion.extents.x1, visRegion.extents.y1, visRegion.extents.x2, visRegion.extents.y2, + nrectangles); + #endif + + pBox = nxagentGetOptimizedRegionBoxes(&visRegion); + + for (i = 0; i < nrectangles; i++) + { + if (pBox[i].x1 == 0 && pBox[i].y1 == 0 && + pBox[i].x2 == 0 && pBox[i].y2 == 0) + { + continue; + } + + XDrawRectangle(nxagentDisplay, nxagentWindow(pWin), gc, + pBox[i].x1, pBox[i].y1, pBox[i].x2 - pBox[i].x1 - 1, + pBox[i].y2 - pBox[i].y1 - 1); + } + + XFreeGC(nxagentDisplay, gc); + + RegionUninit(&visRegion); +} + +void nxagentRegionsOnScreen() +{ + FindClientResourcesByType(clients[serverClient -> index], RT_NX_CORR_WINDOW, + nxagentCorruptedRegionOnWindow, NULL); +} + +#endif + +/* + * If the synchronization loop breaks and the + * drawable synchronization cannot be completed, + * the remaining data is stored in a bitmap. + * The synchronization loop is then restarted + * using the bitmap as source instead of the + * drawable. + */ + +void nxagentCreateDrawableBitmap(DrawablePtr pDrawable) +{ + PixmapPtr pBitmap; + GCPtr pGC = NULL; + RegionPtr pClipRegion = NullRegion; + + int x, y; + int w, h; + int saveTrap; + + #ifdef TEST + fprintf(stderr, "nxagentCreateDrawableBitmap: Creating synchronization bitmap for [%s] at [%p].\n", + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + /* + * The bitmap is created only in the + * nxagent. + */ + + saveTrap = nxagentGCTrap; + + nxagentGCTrap = 1; + + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentCreateDrawableBitmap: The drawable is already synchronized. Skipping bitmap creation.\n"); + #endif + + goto nxagentCreateDrawableBitmapEnd; + } + + /* + * Should create a function to append + * a bitmap to another, instead of de- + * stroy the old one. + */ + + if (nxagentDrawableBitmap(pDrawable) != NullPixmap) + { + #ifdef WARNING + fprintf(stderr, "nxagentCreateDrawableBitmap: WARNING! Going to replace the bitmap at [%p] with corrupted [%d,%d,%d,%d].\n", + (void *) nxagentDrawableBitmap(pDrawable), + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x1, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y1, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x2, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y2); + #endif + + nxagentDestroyDrawableBitmap(pDrawable); + } + + /* + * Clipping to the visible area. + */ + + pClipRegion = nxagentCreateRegion(pDrawable, NULL, 0, 0, pDrawable -> width, pDrawable -> height); + + RegionIntersect(pClipRegion, pClipRegion, nxagentCorruptedRegion(pDrawable)); + + if (RegionNil(pClipRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentCreateDrawableBitmap: The corrupted region is not visible. Skipping bitmap creation.\n"); + #endif + + goto nxagentCreateDrawableBitmapEnd; + } + + /* + * FIXME: A better way it would be create the bitmap + * with the same extents of the clipRegion. This + * requires to save the offset with respect to the + * drawable origin like in the backing store. This + * becomes particularly important when the drawable + * is a huge window, because the pixmap creation + * would fail. + */ + + pBitmap = nxagentCreatePixmap(pDrawable -> pScreen, pDrawable -> width, pDrawable -> height, pDrawable -> depth, 0); + + if (pBitmap == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentCreateDrawableBitmap: Cannot create pixmap for the bitmap data.\n"); + #endif + + goto nxagentCreateDrawableBitmapEnd; + } + + pGC = GetScratchGC(pBitmap -> drawable.depth, pBitmap -> drawable.pScreen); + + ValidateGC((DrawablePtr) pBitmap, pGC); + + x = pClipRegion -> extents.x1; + y = pClipRegion -> extents.y1; + w = pClipRegion -> extents.x2 - pClipRegion -> extents.x1; + h = pClipRegion -> extents.y2 - pClipRegion -> extents.y1; + + nxagentCopyArea(pDrawable, (DrawablePtr) pBitmap, pGC, x, y, w, h, x, y); + + RegionUnion(nxagentCorruptedRegion((DrawablePtr) pBitmap), + nxagentCorruptedRegion((DrawablePtr) pBitmap), pClipRegion); + + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentPixmapPriv(nxagentRealPixmap((PixmapPtr) pDrawable)) -> synchronizationBitmap = pBitmap; + + if (nxagentIsCorruptedBackground((PixmapPtr) pDrawable) == 1) + { + nxagentSynchronization.backgroundBitmaps++; + } + else + { + nxagentSynchronization.pixmapBitmaps++; + } + } + else + { + nxagentWindowPriv((WindowPtr) pDrawable) -> synchronizationBitmap = pBitmap; + + nxagentSynchronization.windowBitmaps++; + } + + #ifdef TEST + fprintf(stderr, "nxagentCreateDrawableBitmap: Drawable [%p] has bitmap at [%p] with corrupted [%d,%d,%d,%d].\n", + (void *) pDrawable, (void *) nxagentDrawableBitmap(pDrawable), + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x1, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y1, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.x2, + nxagentCorruptedRegion((DrawablePtr) nxagentDrawableBitmap(pDrawable)) -> extents.y2); + #endif + +nxagentCreateDrawableBitmapEnd: + + nxagentGCTrap = saveTrap; + + if (pClipRegion != NullRegion) + { + nxagentFreeRegion(pDrawable, pClipRegion); + } + + if (pGC != NULL) + { + FreeScratchGC(pGC); + } +} + +void nxagentDestroyDrawableBitmap(DrawablePtr pDrawable) +{ + if (nxagentDrawableBitmap(pDrawable) != NullPixmap) + { + #ifdef TEST + fprintf(stderr, "nxagentDestroyDrawableBitmap: Destroying bitmap for drawable at [%p].\n", + (void *) pDrawable); + #endif + + nxagentDestroyPixmap(nxagentDrawableBitmap(pDrawable)); + + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentPixmapPriv(nxagentRealPixmap((PixmapPtr) pDrawable)) -> synchronizationBitmap = NullPixmap; + + if (nxagentIsCorruptedBackground((PixmapPtr) pDrawable) == 1) + { + nxagentSynchronization.backgroundBitmaps--; + } + else + { + nxagentSynchronization.pixmapBitmaps--; + } + } + else + { + nxagentWindowPriv((WindowPtr) pDrawable) -> synchronizationBitmap = NullPixmap; + + nxagentSynchronization.windowBitmaps--; + } + } +} + +void nxagentIncreasePixmapUsageCounter(PixmapPtr pPixmap) +{ + if (nxagentDrawableStatus((DrawablePtr) pPixmap) == Synchronized) + { + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentIncreasePixmapUsageCounter: Pixmap usage counter was [%d].\n", + nxagentPixmapUsageCounter(pPixmap)); + #endif + + nxagentPixmapUsageCounter(pPixmap) += 1; + + nxagentAllocateCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP); +} + +void nxagentAllocateCorruptedResource(DrawablePtr pDrawable, RESTYPE type) +{ + PixmapPtr pRealPixmap; + + if (nxagentSessionState == SESSION_DOWN) + { + #ifdef TEST + fprintf(stderr, "nxagentAllocateCorruptedResource: WARNING! Not allocated corrupted resource " + "[%s][%p] with the display down.\n", nxagentDrawableType(pDrawable), + (void *) pDrawable); + #endif + + return; + } + + if (type == RT_NX_CORR_WINDOW) + { + if (nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentAllocateCorruptedResource: New resource at [%p]. Corrupted " + "windows counter was [%d].\n", (void *) pDrawable, nxagentCorruptedWindows); + #endif + + nxagentCorruptedWindows++; + + nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId = FakeClientID(serverClient -> index); + + AddResource(nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId, RT_NX_CORR_WINDOW, + (void *) pDrawable); + } + } + else if (type == RT_NX_CORR_BACKGROUND) + { + pRealPixmap = nxagentRealPixmap((PixmapPtr) pDrawable); + + if (nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId == 0) + { + /* + * When a pixmap is added to the background + * corrupted resources, it must be removed + * from the pixmap corrupted resources. + */ + + nxagentDestroyCorruptedResource(pDrawable, RT_NX_CORR_PIXMAP); + + #ifdef TEST + fprintf(stderr, "nxagentAllocateCorruptedResource: New resource at [%p]. Corrupted " + "backgrounds counter was [%d].\n", (void *) pDrawable, nxagentCorruptedBackgrounds); + #endif + + nxagentCorruptedBackgrounds++; + + nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId = FakeClientID(serverClient -> index); + + AddResource(nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId, RT_NX_CORR_BACKGROUND, + (void *) pRealPixmap); + } + } + else if (type == RT_NX_CORR_PIXMAP) + { + /* + * The shared memory pixmaps are always dirty + * and shouldn't be synchronized. + */ + + if (nxagentPixmapUsageCounter((PixmapPtr) pDrawable) >= MINIMUM_PIXMAP_USAGE_COUNTER && + nxagentIsShmPixmap((PixmapPtr) pDrawable) == 0) + { + pRealPixmap = nxagentRealPixmap((PixmapPtr) pDrawable); + + if (nxagentPixmapPriv(pRealPixmap) -> corruptedId == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentAllocateCorruptedResource: New resource at [%p]. Corrupted " + "pixmaps counter was [%d].\n", (void *) pDrawable, nxagentCorruptedPixmaps); + #endif + + nxagentCorruptedPixmaps++; + + nxagentPixmapPriv(pRealPixmap) -> corruptedId = FakeClientID(serverClient -> index); + + AddResource(nxagentPixmapPriv(pRealPixmap) -> corruptedId, RT_NX_CORR_PIXMAP, + (void *) pRealPixmap); + } + } + } +} + +void nxagentDestroyCorruptedResource(DrawablePtr pDrawable, RESTYPE type) +{ + PixmapPtr pRealPixmap; + + if (type == RT_NX_CORR_WINDOW) + { + if (nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentDestroyCorruptedResource: Removing resource at [%p]. Corrupted " + "windows counter was [%d].\n", (void *) pDrawable, nxagentCorruptedWindows); + #endif + + if (nxagentCorruptedWindows > 0) + { + nxagentCorruptedWindows--; + } + + FreeResource(nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedId, RT_NONE); + + if (nxagentSynchronization.pDrawable == pDrawable) + { + nxagentSynchronization.pDrawable = NULL; + } + } + } + else if (type == RT_NX_CORR_BACKGROUND) + { + pRealPixmap = nxagentRealPixmap((PixmapPtr) pDrawable); + + if (nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentDestroyCorruptedResource: Removing resource at [%p]. Corrupted " + "backgrounds counter was [%d].\n", (void *) pDrawable, nxagentCorruptedBackgrounds); + #endif + + if (nxagentCorruptedBackgrounds > 0) + { + nxagentCorruptedBackgrounds--; + } + + FreeResource(nxagentPixmapPriv(pRealPixmap) -> corruptedBackgroundId, RT_NONE); + + if (nxagentSynchronization.pDrawable == pDrawable) + { + nxagentSynchronization.pDrawable = NULL; + } + } + } + else if (type == RT_NX_CORR_PIXMAP) + { + pRealPixmap = nxagentRealPixmap((PixmapPtr) pDrawable); + + if (nxagentPixmapPriv(pRealPixmap) -> corruptedId != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentDestroyCorruptedResource: Removing resource at [%p]. Corrupted " + "pixmaps counter was [%d].\n", (void *) pDrawable, nxagentCorruptedPixmaps); + #endif + + if (nxagentCorruptedPixmaps > 0) + { + nxagentCorruptedPixmaps--; + } + + FreeResource(nxagentPixmapPriv(pRealPixmap) -> corruptedId, RT_NONE); + + if (nxagentSynchronization.pDrawable == pDrawable) + { + nxagentSynchronization.pDrawable = NULL; + } + } + } +} + +void nxagentCleanCorruptedDrawable(DrawablePtr pDrawable) +{ + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentCleanCorruptedDrawable: Clearing out the corrupted drawable [%s][%p].\n", + nxagentDrawableType(pDrawable), (void *) pDrawable); + #endif + + nxagentUnmarkCorruptedRegion(pDrawable, NullRegion); + + if (nxagentDrawableBitmap(pDrawable) != NullPixmap) + { + nxagentDestroyDrawableBitmap(pDrawable); + } +} + +void nxagentUnmarkExposedRegion(WindowPtr pWin, RegionPtr pRegion, RegionPtr pOther) +{ + RegionRec clipRegion; + + if (pRegion != NullRegion && RegionNil(pRegion) == 0 && + nxagentDrawableStatus((DrawablePtr) pWin) == NotSynchronized) + { + RegionInit(&clipRegion, NullBox, 1); + + RegionCopy(&clipRegion, pRegion); + + if (pOther != NullRegion && RegionNil(pOther) == 0) + { + RegionUnion(&clipRegion, &clipRegion, pOther); + } + + RegionTranslate(&clipRegion, -pWin -> drawable.x, -pWin -> drawable.y); + + #ifdef TEST + fprintf(stderr, "nxagentUnmarkExposedRegion: Validating expose region [%d,%d,%d,%d] " + "on window [%p].\n", clipRegion.extents.x1, clipRegion.extents.y1, + clipRegion.extents.x2, clipRegion.extents.y2, (void *) pWin); + #endif + + nxagentUnmarkCorruptedRegion((DrawablePtr) pWin, &clipRegion); + + RegionUninit(&clipRegion); + } +} + +int nxagentSynchronizationPredicate() +{ + if (nxagentCorruptedWindows == 0 && + nxagentCorruptedBackgrounds == 0 && + nxagentCorruptedPixmaps == 0) + { + return NotNeeded; + } + + if (nxagentBlocking == 0 && + nxagentCongestion <= 4 && + nxagentReady == 0 && + nxagentUserInput(NULL) == 0) + { + return Needed; + } + + /* + * If there are resources to synchronize + * but the conditions to start the loop + * are not satisfied, a little delay is + * requested to check for a new loop as + * soon as possible. + */ + + return Delayed; +} + +void nxagentSendBackgroundExpose(WindowPtr pWin, PixmapPtr pBackground, RegionPtr pExpose) +{ + RegionRec expose; + miBSWindowPtr pBackingStore; + + RegionInit(&expose, NullBox, 1); + + #ifdef DEBUG + fprintf(stderr, "nxagentSendBackgroundExpose: Original expose region is [%d,%d,%d,%d].\n", + pExpose -> extents.x1, pExpose -> extents.y1, + pExpose -> extents.x2, pExpose -> extents.y2); + + fprintf(stderr, "nxagentSendBackgroundExpose: Window clipList is [%d,%d,%d,%d].\n", + pWin -> clipList.extents.x1, pWin -> clipList.extents.y1, + pWin -> clipList.extents.x2, pWin -> clipList.extents.y2); + #endif + + if (nxagentDrawableStatus((DrawablePtr) pBackground) == Synchronized && + (pBackground -> drawable.width < pWin -> drawable.width || + pBackground -> drawable.height < pWin -> drawable.height)) + { + #ifdef TEST + fprintf(stderr, "nxagentSendBackgroundExpose: Pixmap background [%dx%d] is " + "smaller than window [%dx%d]. Going to expose the winSize.\n", + pBackground -> drawable.width, pBackground -> drawable.height, + pWin -> drawable.width, pWin -> drawable.height); + #endif + + RegionCopy(&expose, &pWin -> winSize); + } + else + { + RegionCopy(&expose, pExpose); + + RegionTranslate(&expose, pWin -> drawable.x, pWin -> drawable.y); + } + + RegionSubtract(&expose, &expose, nxagentCorruptedRegion((DrawablePtr) pWin)); + + if (RegionNil(&pWin -> clipList) != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSendBackgroundExpose: Exposures deferred because the window " + "is hidden.\n"); + #endif + + RegionUnion(nxagentDeferredBackgroundExposures, + nxagentDeferredBackgroundExposures, &expose); + + nxagentWindowPriv(pWin) -> deferredBackgroundExpose = 1; + + goto nxagentSendBackgroundExposeEnd; + } + + #ifdef TEST + fprintf(stderr, "nxagentSendBackgroundExpose: Sending expose [%d,%d,%d,%d].\n", + expose.extents.x1, expose.extents.y1, expose.extents.x2, expose.extents.y2); + #endif + + /* + * This prevents hidden region to be exposed. + */ + + pBackingStore = (miBSWindowPtr)pWin->backStorage; + + if ((pBackingStore != NULL) && (RegionNil(&pBackingStore->SavedRegion) == 0)) + { + RegionTranslate(&expose, -pWin -> drawable.x, -pWin -> drawable.y); + + RegionSubtract(&expose, &expose, &pBackingStore -> SavedRegion); + + RegionTranslate(&expose, pWin -> drawable.x, pWin -> drawable.y); + } + + RegionIntersect(&expose, &expose, &pWin -> clipList); + + /* + * Reduce the overall region to expose. + */ + + RegionTranslate(&expose, -pWin -> drawable.x, -pWin -> drawable.y); + + RegionSubtract(pExpose, pExpose, &expose); + + RegionTranslate(&expose, pWin -> drawable.x, pWin -> drawable.y); + + miWindowExposures(pWin, &expose, &expose); + +nxagentSendBackgroundExposeEnd: + + RegionUninit(&expose); +} + +void nxagentExposeBackgroundPredicate(void *p0, XID x1, void *p2) +{ + WindowPtr pWin = (WindowPtr) p0; + WindowPtr pParent; + + struct nxagentExposeBackground *pPair = p2; + + if (RegionNil(pPair -> pExpose) != 0) + { + return; + } + + if (pWin -> backgroundState == BackgroundPixmap && + pWin -> background.pixmap == pPair -> pBackground) + { + #ifdef TEST + fprintf(stderr, "nxagentExposeBackgroundPredicate: Window at [%p] uses pixmap [%p] " + "as background.\n", (void *) pWin, (void *) pPair -> pBackground); + #endif + + nxagentSendBackgroundExpose(pWin, pPair -> pBackground, pPair -> pExpose); + } + else if (pWin -> backgroundState == ParentRelative) + { + #ifdef TEST + fprintf(stderr, "nxagentExposeBackgroundPredicate: Window [%p] uses parent's background.\n", + (void *) pWin); + #endif + + pParent = pWin -> parent; + + while (pParent != NULL) + { + if (pParent -> backgroundState == BackgroundPixmap && + pParent -> background.pixmap == pPair -> pBackground) + { + #ifdef TEST + fprintf(stderr, "nxagentExposeBackgroundPredicate: Parent window at [%p] uses pixmap [%p] " + "as background.\n", (void *) pParent, (void *) pPair -> pBackground); + #endif + + nxagentSendBackgroundExpose(pWin, pPair -> pBackground, pPair -> pExpose); + + break; + } + + pParent = pParent -> parent; + } + } +} + +/* + * This function is similar to nxagentClipAndSendExpose(). + */ + +int nxagentClipAndSendClearExpose(WindowPtr pWin, void * ptr) +{ + RegionPtr exposeRgn; + RegionPtr remoteExposeRgn; + + #ifdef DEBUG + BoxRec box; + #endif + + remoteExposeRgn = (RegionRec *) ptr; + + if (nxagentWindowPriv(pWin) -> deferredBackgroundExpose == 1) + { + exposeRgn = RegionCreate(NULL, 1); + + #ifdef DEBUG + box = *RegionExtents(remoteExposeRgn); + + fprintf(stderr, "nxagentClipAndSendClearExpose: Background expose extents: [%d,%d,%d,%d].\n", + box.x1, box.y1, box.x2, box.y2); + + box = *RegionExtents(&pWin -> clipList); + + fprintf(stderr, "nxagentClipAndSendClearExpose: Clip list extents for window at [%p]: [%d,%d,%d,%d].\n", + (void *) pWin, box.x1, box.y1, box.x2, box.y2); + #endif + + RegionIntersect(exposeRgn, remoteExposeRgn, &pWin -> clipList); + + /* + * If the region will be synchronized, + * the expose on corrupted regions can + * be ignored. + */ + + RegionSubtract(exposeRgn, exposeRgn, nxagentCorruptedRegion((DrawablePtr) pWin)); + + if (RegionNotEmpty(exposeRgn)) + { + #ifdef DEBUG + box = *RegionExtents(exposeRgn); + + fprintf(stderr, "nxagentClipAndSendClearExpose: Forwarding expose [%d,%d,%d,%d] to window at [%p] pWin.\n", + box.x1, box.y1, box.x2, box.y2, (void *) pWin); + #endif + + RegionSubtract(remoteExposeRgn, remoteExposeRgn, exposeRgn); + + miWindowExposures(pWin, exposeRgn, exposeRgn); + } + + RegionDestroy(exposeRgn); + + nxagentWindowPriv(pWin) -> deferredBackgroundExpose = 0; + } + + if (RegionNotEmpty(remoteExposeRgn)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentClipAndSendClearExpose: Region not empty. Walk children.\n"); + #endif + + + return WT_WALKCHILDREN; + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentClipAndSendClearExpose: Region empty. Stop walking.\n"); + #endif + + return WT_STOPWALKING; + } +} + +void nxagentSendDeferredBackgroundExposures(void) +{ + if (nxagentDeferredBackgroundExposures == NullRegion) + { + nxagentDeferredBackgroundExposures = RegionCreate(NullBox, 1); + } + + if (RegionNotEmpty(nxagentDeferredBackgroundExposures) != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSendDeferredBackgroundExposures: Going to send deferred exposures to the root window.\n"); + #endif + + TraverseTree(screenInfo.screens[0]->root, nxagentClipAndSendClearExpose, (void *) nxagentDeferredBackgroundExposures); + + RegionEmpty(nxagentDeferredBackgroundExposures); + } +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Drawable.h b/nx-X11/programs/Xserver/hw/nxagent/Drawable.h new file mode 100644 index 000000000..6388d5c12 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Drawable.h @@ -0,0 +1,229 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Drawable_H__ +#define __Drawable_H__ + +#include "resource.h" +#include "Windows.h" +#include "Pixmaps.h" + +/* + * Structures and macros used to manage the Lazy encoding. + */ + +typedef struct +{ + DrawablePtr pDrawable; + int drawableType; + int abort; + int windowBitmaps; + int pixmapBitmaps; + int backgroundBitmaps; + +} _nxagentSynchronizationRec; + +extern _nxagentSynchronizationRec nxagentSynchronization; + +enum DrawableStatus +{ + Synchronized, + NotSynchronized +}; + +enum SynchronizationPredicate +{ + Needed, + NotNeeded, + Delayed +}; + +/* + * Shall the synchronization wait for the + * drawable wakening? + */ + +#define DONT_WAIT 0 +#define DO_WAIT 1 + +/* + * How the synchronization loop can be + * interrupted? A 0 mask means that the + * loop can't be stopped. + */ + +#define EVENT_BREAK (1 << 0) +#define CONGESTION_BREAK (1 << 1) +#define BLOCKING_BREAK (1 << 2) + +#define NEVER_BREAK 0 +#define ALWAYS_BREAK (EVENT_BREAK | \ + CONGESTION_BREAK | \ + BLOCKING_BREAK) + +/* + * Minimum value of usage counter which + * a pixmap should have to be synchronized. + */ + +#define MINIMUM_PIXMAP_USAGE_COUNTER 2 + +/* + * This is the macro used to get the external XID + * from a generic pointer to a drawable. + */ + +#define nxagentDrawable(pDrawable) \ + ((pDrawable)->type == DRAWABLE_WINDOW ? \ + nxagentWindow((WindowPtr)pDrawable) : \ + nxagentPixmap((PixmapPtr)pDrawable)) + +#define nxagentVirtualDrawable(pDrawable) \ + (DrawablePtr)((pDrawable)->type == DRAWABLE_WINDOW ? \ + NULL : nxagentVirtualPixmap((PixmapPtr)pDrawable)) + +#define nxagentDrawablePicture(pDrawable) \ + ((DrawablePtr)((pDrawable)->type == DRAWABLE_WINDOW ? \ + nxagentWindowPriv((WindowPtr)pDrawable) -> pPicture : \ + nxagentPixmapPriv((PixmapPtr)pDrawable) -> pPicture)) + +#define nxagentCorruptedRegion(pDrawable) \ + ((pDrawable) -> type == DRAWABLE_PIXMAP ? \ + nxagentPixmapCorruptedRegion((PixmapPtr) pDrawable) : \ + nxagentWindowCorruptedRegion((WindowPtr) pDrawable)) + +#define nxagentDrawableStatus(pDrawable) \ + (RegionNil(nxagentCorruptedRegion(pDrawable)) ? \ + Synchronized : NotSynchronized) + +#define nxagentDrawableContainGlyphs(pDrawable) \ + ((pDrawable) -> type == DRAWABLE_PIXMAP ? \ + nxagentPixmapContainGlyphs((PixmapPtr) (pDrawable)) : \ + nxagentWindowContainGlyphs((WindowPtr) (pDrawable))) + +#define nxagentSetDrawableContainGlyphs(pDrawable, value) \ +do \ +{ \ + if ((pDrawable) -> type == DRAWABLE_PIXMAP) \ + { \ + nxagentPixmapContainGlyphs(nxagentRealPixmap((PixmapPtr) (pDrawable))) = (value); \ + } \ + else \ + { \ + nxagentWindowContainGlyphs((WindowPtr) (pDrawable)) = (value); \ + } \ +} while (0) + +#define nxagentDrawableBitmap(pDrawable) \ + ((pDrawable) -> type == DRAWABLE_PIXMAP ? \ + nxagentPixmapPriv(nxagentRealPixmap((PixmapPtr) (pDrawable))) -> synchronizationBitmap : \ + nxagentWindowPriv((WindowPtr) (pDrawable)) -> synchronizationBitmap) + +#define nxagentDrawableTimestamp(pDrawable) \ + ((pDrawable) -> type == DRAWABLE_PIXMAP ? \ + nxagentPixmapTimestamp((PixmapPtr) pDrawable) : \ + nxagentWindowTimestamp((WindowPtr) pDrawable)) + +#define nxagentDrawableType(pDrawable) \ + ((pDrawable) -> type == DRAWABLE_PIXMAP ? "pixmap" : "window") + +extern RESTYPE RT_NX_CORR_BACKGROUND; +extern RESTYPE RT_NX_CORR_WINDOW; +extern RESTYPE RT_NX_CORR_PIXMAP; + +extern int nxagentCorruptedPixmaps; +extern int nxagentCorruptedWindows; +extern int nxagentCorruptedBackgrounds; + +extern int nxagentForceSynchronization; + +extern RegionPtr nxagentCreateRegion(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int width, int height); + +#define nxagentFreeRegion(pDrawable, pRegion) \ + RegionDestroy(pRegion); + +extern void nxagentMarkCorruptedRegion(DrawablePtr pDrawable, RegionPtr pRegion); +extern void nxagentUnmarkCorruptedRegion(DrawablePtr pDrawable, RegionPtr pRegion); +extern void nxagentMoveCorruptedRegion(WindowPtr pWin, unsigned int mask); +extern void nxagentIncreasePixmapUsageCounter(PixmapPtr pPixmap); + +extern int nxagentSynchronizeRegion(DrawablePtr pDrawable, RegionPtr pRegion, unsigned int breakMask, WindowPtr owner); +extern void nxagentSynchronizeBox(DrawablePtr pDrawable, BoxPtr pBox, unsigned int breakMask); +extern int nxagentSynchronizeDrawable(DrawablePtr pDrawable, int wait, unsigned int breakMask, WindowPtr owner); +extern int nxagentSynchronizeDrawableData(DrawablePtr pDrawable, unsigned int breakMask, WindowPtr owner); +extern void nxagentSynchronizationLoop(unsigned int mask); + +extern int nxagentSynchronizationPredicate(void); + +extern BoxPtr nxagentGetOptimizedRegionBoxes(RegionPtr pRegion); + +extern void nxagentCleanCorruptedDrawable(DrawablePtr pDrawable); + +extern void nxagentUnmarkExposedRegion(WindowPtr pWin, RegionPtr pRegion, RegionPtr pOther); +extern void nxagentSendDeferredBackgroundExposures(void); + +extern void nxagentClearRegion(DrawablePtr pDrawable, RegionPtr pRegion); +extern void nxagentFillRemoteRegion(DrawablePtr pDrawable, RegionPtr pRegion); + +extern void nxagentAllocateCorruptedResource(DrawablePtr pDrawable, RESTYPE type); +extern void nxagentDestroyCorruptedResource(DrawablePtr pDrawable, RESTYPE type); +extern int nxagentDestroyCorruptedBackgroundResource(void * p, XID id); +extern int nxagentDestroyCorruptedWindowResource(void * p, XID id); +extern int nxagentDestroyCorruptedPixmapResource(void * p, XID id); + +extern void nxagentCreateDrawableBitmap(DrawablePtr pDrawable); +extern void nxagentDestroyDrawableBitmap(DrawablePtr pDrawable); + +extern void nxagentRegionsOnScreen(void); + +#define PRINT_REGION_BOXES(pRegion, strRegion) \ +do \ +{ \ + int i; \ + int numRects; \ + BoxPtr pBox; \ +\ + if (pRegion == NullRegion) \ + { \ + fprintf(stderr, "printRegionBoxes:: Region " strRegion " is null.\n"); \ + break; \ + } \ +\ + numRects = RegionNumRects(pRegion); \ + pBox = RegionRects(pRegion); \ +\ + fprintf(stderr, "printRegionBoxes:: Region " strRegion " at [%p] has [%d] boxes:\n", \ + (void *) (pRegion), numRects); \ +\ + for (i = 0; i < numRects; i++) \ + { \ + fprintf(stderr, "[%d] [%d,%d,%d,%d]\n", \ + i, pBox[i].x1, pBox[i].y1, pBox[i].x2, pBox[i].y2); \ + } \ +\ +} while (0) + +#endif /* __Drawable_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Error.c b/nx-X11/programs/Xserver/hw/nxagent/Error.c new file mode 100644 index 000000000..05d0f3081 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Error.c @@ -0,0 +1,644 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> + +#include "os.h" + +#include "scrnintstr.h" +#include "Agent.h" + +#include "Xlib.h" +#include "Xproto.h" + +#include "Error.h" +#include "Args.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + + +/* + * Duplicated stderr file descriptor. + */ + +static int nxagentStderrDup = -1; + +/* + * Saved stderr file descriptor. + */ + +static int nxagentStderrBackup = -1; + +/* + * Clients log file descriptor. + */ + +static int nxagentClientsLog = -1; + +#define DEFAULT_STRING_LENGTH 256 + + +/* + * Clients log file name. + */ + +char nxagentClientsLogName[DEFAULT_STRING_LENGTH] = { 0 }; + +/* + * User's home. + */ + +static char nxagentHomeDir[DEFAULT_STRING_LENGTH] = { 0 }; + +/* + * NX root directory. + */ + +static char nxagentRootDir[DEFAULT_STRING_LENGTH] = { 0 }; + +/* + * Session log Directory. + */ + +static char nxagentSessionDir[DEFAULT_STRING_LENGTH] = { 0 }; + +char *nxagentGetClientsPath(void); + +static int nxagentPrintError(Display *dpy, XErrorEvent *event, FILE *fp); + +/* declare an error handler that does not exit when an error + * event is catched. + */ + +int nxagentErrorHandler(Display *dpy, XErrorEvent *event) +{ + if (nxagentVerbose == 1) + { + nxagentPrintError(dpy, event, stderr); + } + + return 0; +} + +/* copied from XlibInt.c */ +/* extension stuff roughly commented out */ +static int nxagentPrintError(dpy, event, fp) + Display *dpy; + XErrorEvent *event; + FILE *fp; +{ + char buffer[BUFSIZ]; + char mesg[BUFSIZ]; + char number[32]; + char *mtype = "XlibMessage"; + /* + register _XExtension *ext = (_XExtension *)NULL; + _XExtension *bext = (_XExtension *)NULL; + */ + XGetErrorText(dpy, event->error_code, buffer, BUFSIZ); + XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ); + (void) fprintf(fp, "%s: %s\n ", mesg, buffer); + XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", + mesg, BUFSIZ); + (void) fprintf(fp, mesg, event->request_code); + if (event->request_code < 128) { + sprintf(number, "%d", event->request_code); + XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ); + } else { + /* for (ext = dpy->ext_procs; + ext && (ext->codes.major_opcode != event->request_code); + ext = ext->next) + ; + if (ext) + strcpy(buffer, ext->name); + else + */ + buffer[0] = '\0'; + } + (void) fprintf(fp, " (%s)\n", buffer); + if (event->request_code >= 128) { + XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d", + mesg, BUFSIZ); + fputs(" ", fp); + (void) fprintf(fp, mesg, event->minor_code); + /* + if (ext) { + sprintf(mesg, "%s.%d", ext->name, event->minor_code); + XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ); + (void) fprintf(fp, " (%s)", buffer); + } + */ + fputs("\n", fp); + } + if (event->error_code >= 128) { + /* kludge, try to find the extension that caused it */ + buffer[0] = '\0'; + /* + for (ext = dpy->ext_procs; ext; ext = ext->next) { + if (ext->error_string) + (*ext->error_string)(dpy, event->error_code, &ext->codes, + buffer, BUFSIZ); + if (buffer[0]) { + bext = ext; + break; + } + if (ext->codes.first_error && + ext->codes.first_error < (int)event->error_code && + (!bext || ext->codes.first_error > bext->codes.first_error)) + bext = ext; + } + if (bext) + sprintf(buffer, "%s.%d", bext->name, + event->error_code - bext->codes.first_error); + else + */ + strcpy(buffer, "Value"); + XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ); + if (mesg[0]) { + fputs(" ", fp); + (void) fprintf(fp, mesg, event->resourceid); + fputs("\n", fp); + } + /* let extensions try to print the values */ + /* + for (ext = dpy->ext_procs; ext; ext = ext->next) { + if (ext->error_values) + (*ext->error_values)(dpy, event, fp); + } + */ + } else if ((event->error_code == BadWindow) || + (event->error_code == BadPixmap) || + (event->error_code == BadCursor) || + (event->error_code == BadFont) || + (event->error_code == BadDrawable) || + (event->error_code == BadColor) || + (event->error_code == BadGC) || + (event->error_code == BadIDChoice) || + (event->error_code == BadValue) || + (event->error_code == BadAtom)) { + if (event->error_code == BadValue) + XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x", + mesg, BUFSIZ); + else if (event->error_code == BadAtom) + XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x", + mesg, BUFSIZ); + else + XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x", + mesg, BUFSIZ); + fputs(" ", fp); + (void) fprintf(fp, mesg, event->resourceid); + fputs("\n", fp); + } + XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", + mesg, BUFSIZ); + fputs(" ", fp); + (void) fprintf(fp, mesg, event->serial); + XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d", + mesg, BUFSIZ); + fputs("\n ", fp); + /* (void) fprintf(fp, mesg, dpy->request); */ + fputs("\n", fp); + if (event->error_code == BadImplementation) return 0; + return 1; +} + +int nxagentExitHandler(const char *message) +{ + FatalError("%s", message); + + return 0; +} + +void nxagentOpenClientsLogFile() +{ + char * clientsLogName; + + if (*nxagentClientsLogName == '\0') + { + clientsLogName = nxagentGetClientsPath(); + + if (clientsLogName != NULL) + { + free(clientsLogName); + } + } + + if (nxagentClientsLogName != NULL && *nxagentClientsLogName !='\0') + { + nxagentClientsLog = open(nxagentClientsLogName, O_RDWR | O_CREAT | O_APPEND, 0600); + + if (nxagentClientsLog == -1) + { + fprintf(stderr, "Warning: Failed to open clients log. Error is %d '%s'.\n", + errno, strerror(errno)); + } + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentOpenClientsLogFile: Cannot open clients log file. The path does not exist.\n"); + #endif + } +} + +void nxagentCloseClientsLogFile(void) +{ + close(nxagentClientsLog); +} + +void nxagentStartRedirectToClientsLog(void) +{ + nxagentOpenClientsLogFile(); + + if (nxagentClientsLog != -1) + { + if (nxagentStderrBackup == -1) + { + nxagentStderrBackup = dup(2); + } + + if (nxagentStderrBackup != -1) + { + nxagentStderrDup = dup2(nxagentClientsLog, 2); + + if (nxagentStderrDup == -1) + { + fprintf(stderr, "Warning: Failed to redirect stderr. Error is %d '%s'.\n", + errno, strerror(errno)); + } + } + else + { + fprintf(stderr, "Warning: Failed to backup stderr. Error is %d '%s'.\n", + errno, strerror(errno)); + } + } +} + +void nxagentEndRedirectToClientsLog(void) +{ + if (nxagentStderrBackup != -1) + { + nxagentStderrDup = dup2(nxagentStderrBackup, 2); + + if (nxagentStderrDup == -1) + { + fprintf(stderr, "Warning: Failed to restore stderr. Error is %d '%s'.\n", + errno, strerror(errno)); + } + } + + nxagentCloseClientsLogFile(); +} + +char *nxagentGetHomePath(void) +{ + char *homeEnv; + char *homePath; + + if (*nxagentHomeDir == '\0') + { + /* + * Check the NX_HOME environment. + */ + + homeEnv = getenv("NX_HOME"); + + if (homeEnv == NULL || *homeEnv == '\0') + { + #ifdef TEST + fprintf(stderr, "nxagentGetHomePath: No environment for NX_HOME.\n"); + #endif + + homeEnv = getenv("HOME"); + + if (homeEnv == NULL || *homeEnv == '\0') + { + #ifdef PANIC + fprintf(stderr, "nxagentGetHomePath: PANIC! No environment for HOME.\n"); + #endif + + return NULL; + } + } + + if (strlen(homeEnv) > DEFAULT_STRING_LENGTH - 1) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetHomePath: PANIC! Invalid value for the NX " + "home directory '%s'.\n", homeEnv); + #endif + } + + strncpy(nxagentHomeDir, homeEnv, DEFAULT_STRING_LENGTH - 1); + + #ifdef TEST + fprintf(stderr, "nxagentGetHomePath: Assuming NX user's home directory '%s'.\n", nxagentHomeDir); + #endif + } + + homePath = (char*) malloc(strlen(nxagentHomeDir) + 1); + + if (homePath == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetHomePath: PANIC! Can't allocate memory for the home path.\n"); + #endif + + return NULL; + } + + strcpy(homePath, nxagentHomeDir); + + return homePath; +} + +char *nxagentGetRootPath(void) +{ + char *rootEnv; + char *homeEnv; + char *rootPath; + + struct stat dirStat; + + if (*nxagentRootDir == '\0') + { + /* + * Check the NX_ROOT environment. + */ + + rootEnv = getenv("NX_ROOT"); + + if (rootEnv == NULL || *rootEnv == '\0') + { + #ifdef TEST + fprintf(stderr, "nxagentGetRootPath: WARNING! No environment for NX_ROOT.\n"); + #endif + + /* + * We will determine the root NX directory + * based on the NX_HOME or HOME directory + * settings. + */ + + homeEnv = nxagentGetHomePath(); + + if (homeEnv == NULL) + { + + #ifdef PANIC + #endif + + return NULL; + } + + if (strlen(homeEnv) > DEFAULT_STRING_LENGTH - + strlen("/.nx") - 1) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetRootPath: PANIC! Invalid value for the NX " + "home directory '%s'.\n", homeEnv); + #endif + + free(homeEnv); + + return NULL; + } + + #ifdef TEST + fprintf(stderr, "nxagentGetRootPath: Assuming NX root directory in '%s'.\n", homeEnv); + #endif + + strcpy(nxagentRootDir, homeEnv); + strcat(nxagentRootDir, "/.nx"); + + free(homeEnv); + + /* + * Create the NX root directory. + */ + + if ((stat(nxagentRootDir, &dirStat) == -1) && (errno == ENOENT)) + { + if (mkdir(nxagentRootDir, 0777) < 0 && (errno != EEXIST)) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetRootPath: PANIC! Can't create directory '%s'. Error is %d '%s'.\n", + nxagentRootDir, errno, strerror(errno)); + #endif + + return NULL; + } + } + } + else + { + if (strlen(rootEnv) > DEFAULT_STRING_LENGTH - 1) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetRootPath: PANIC! Invalid value for the NX root directory '%s'.\n", + rootEnv); + #endif + + return NULL; + } + + strcpy(nxagentRootDir, rootEnv); + } + + #ifdef TEST + fprintf(stderr, "nxagentGetRootPath: Assuming NX root directory '%s'.\n", + nxagentRootDir); + #endif + + } + + rootPath = malloc(strlen(nxagentRootDir) + 1); + + if (rootPath == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetRootPath: Can't allocate memory for the root path.\n"); + #endif + + return NULL; + } + + strcpy(rootPath, nxagentRootDir); + + return rootPath; +} + +char *nxagentGetSessionPath(void) +{ + + char *rootPath; + char *sessionPath; + + struct stat dirStat; + + if (*nxagentSessionDir == '\0') + { + /* + * If nxagentSessionId does not exist we + * assume that the sessionPath cannot be + * realized and do not use the clients + * log file. + */ + + if (*nxagentSessionId == '\0') + { + #ifdef TEST + fprintf(stderr, "nxagentGetSessionPath: Session id does not exist. Assuming session path NULL.\n"); + #endif + + return NULL; + } + + rootPath = nxagentGetRootPath(); + + if (rootPath == NULL) + { + return NULL; + } + + strcpy(nxagentSessionDir, rootPath); + + free(rootPath); + + if (strlen(nxagentSessionDir) + strlen("/C-") + strlen(nxagentSessionId) > DEFAULT_STRING_LENGTH - 1) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetSessionPath: PANIC!: Invalid value for the NX session directory '%s'.\n", + nxagentSessionDir); + #endif + + return NULL; + } + + strcat(nxagentSessionDir, "/C-"); + + strcat(nxagentSessionDir, nxagentSessionId); + + if ((stat(nxagentSessionDir, &dirStat) == -1) && (errno == ENOENT)) + { + if (mkdir(nxagentSessionDir, 0777) < 0 && (errno != EEXIST)) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetSessionPath: PANIC! Can't create directory '%s'. Error is %d '%s'.\n", + nxagentSessionDir, errno, strerror(errno)); + #endif + + return NULL; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentGetSessionPath: NX session is '%s'.\n", + nxagentSessionDir); + #endif + + } + + sessionPath = malloc(strlen(nxagentSessionDir) + 1); + + if (sessionPath == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetSessionPath:: PANIC! Can't allocate memory for the session path.\n"); + #endif + + return NULL; + } + + + strcpy(sessionPath, nxagentSessionDir); + + return sessionPath; +} + +char *nxagentGetClientsPath() +{ + char *sessionPath; + char *clientsPath; + + if (*nxagentClientsLogName == '\0') + { + sessionPath = nxagentGetSessionPath(); + + if (sessionPath == NULL) + { + return NULL; + } + + if (strlen(sessionPath) + strlen("/clients") > DEFAULT_STRING_LENGTH - 1) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetClientsPath: PANIC! Invalid value for the NX clients Log File Path '%s'.\n", + nxagentClientsLogName); + #endif + + free(sessionPath); + + return NULL; + } + + strcpy(nxagentClientsLogName, sessionPath); + + strcat(nxagentClientsLogName, "/clients"); + + free(sessionPath); + } + + clientsPath = malloc(strlen(nxagentClientsLogName) + 1); + + if (clientsPath == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentGetClientsPath: PANIC! Can't allocate memory for the clients Log File Path path.\n"); + #endif + + return NULL; + } + + strcpy(clientsPath, nxagentClientsLogName); + + return clientsPath; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Error.h b/nx-X11/programs/Xserver/hw/nxagent/Error.h new file mode 100644 index 000000000..1d0d9a827 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Error.h @@ -0,0 +1,47 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Error_H__ +#define __Error_H__ + +/* + * Clients log file name. + */ + +extern char nxagentClientsLogName[]; + +extern char nxagentVerbose; + +int nxagentErrorHandler(Display *dpy, XErrorEvent *event); + +int nxagentExitHandler(const char *message); + +void nxagentStartRedirectToClientsLog(void); + +void nxagentEndRedirectToClientsLog(void); + +char *nxagentGetSessionPath(void); + +#endif /* __Error_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Events.c b/nx-X11/programs/Xserver/hw/nxagent/Events.c new file mode 100644 index 000000000..e360d21f6 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Events.c @@ -0,0 +1,4767 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "X.h" +#include "signal.h" +#include "unistd.h" +#include "Xproto.h" +#include "screenint.h" +#include "input.h" +#include "dix.h" +#include "misc.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "servermd.h" +#include "mi.h" +#include "selection.h" +#include "keysym.h" +#include "fb.h" +#include "mibstorest.h" +#include "osdep.h" + +#include "Agent.h" +#include "Args.h" +#include "Atoms.h" +#include "Colormap.h" +#include "Display.h" +#include "Screen.h" +#include "Windows.h" +#include "Pixmaps.h" +#include "Keyboard.h" +#include "Keystroke.h" +#include "Events.h" +#include "Pointer.h" +#include "Rootless.h" +#include "Splash.h" +#include "Trap.h" +#include "Dialog.h" +#include "Client.h" +#include "Clipboard.h" +#include "Split.h" +#include "Drawable.h" +#include "Handlers.h" +#include "Utils.h" +#include "Error.h" + +#include <nx/NX.h> +#include <nx/NXvars.h> +#include <nx/NXproto.h> + +#include "xfixesproto.h" +#define Window XlibWindow +#define Atom XlibAtom +#define Time XlibXID +#include "X11/include/Xfixes_nxagent.h" +#undef Window +#undef Atom +#undef Time + +#ifdef NXAGENT_FIXKEYS +#include "inputstr.h" +#include "input.h" +#endif + +#define Time XlibXID +#include "XKBlib.h" +#undef Time + +#define GC XlibGC +#define Font XlibFont +#define KeySym XlibKeySym +#define XID XlibXID +#include "Xlibint.h" +#undef GC +#undef Font +#undef KeySym +#undef XID + +#include <nx-X11/cursorfont.h> + +#include <nx/Shadow.h> +#include "X11/include/Xrandr_nxagent.h" + +#include "compext/Compext.h" + +/* + * Set here the required log level. Please note + * that if you want to enable DEBUG here, then + * you need to enable DEBUG even in Rootless.c + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Log begin and end of the important handlers. + */ + +#undef BLOCKS + +extern Bool nxagentOnce; + +extern WindowPtr nxagentRootTileWindow; +extern int nxagentSplashCount; + +extern int nxagentLastClipboardClient; + +#ifdef NX_DEBUG_INPUT +int nxagentDebugInput = 0; +#endif + +#ifdef DEBUG +extern Bool nxagentRootlessTreesMatch(void); +#endif + +extern Selection *CurrentSelections; +extern int NumCurrentSelections; + +typedef union _XFixesSelectionEvent { + int type; + XFixesSelectionNotifyEvent xfixesselection; + XEvent core; +} XFixesSelectionEvent; + +Bool xkbdRunning = False; +pid_t pidkbd; + +WindowPtr nxagentLastEnteredWindow = NULL; + +PropertyRequestRec nxagentPropertyRequests[NXNumberOfResources]; + +void nxagentHandleCollectPropertyEvent(XEvent*); + +/* + * Finalize the asynchronous handling + * of the X_GrabPointer requests. + */ + +void nxagentHandleCollectGrabPointerEvent(int resource); + +Bool nxagentCollectGrabPointerPredicate(Display *display, XEvent *X, XPointer ptr); + +/* + * Used in Handlers.c to synchronize + * the agent with the remote X server. + */ + +void nxagentHandleCollectInputFocusEvent(int resource); + +/* + * Viewport navigation. + */ + +static int viewportInc = 1; +static enum HandleEventResult viewportLastKeyPressResult; +static int viewportLastX; +static int viewportLastY; +static Cursor viewportCursor; + +#define MAX_INC 200 +#define INC_STEP 5 +#define nextinc(x) ((x) < MAX_INC ? (x) += INC_STEP : (x)) + +/* + * Keyboard and pointer are handled as they were real devices by + * Xnest and we inherit this behaviour. The following mask will + * contain the event mask selected for the root window of the + * agent. All the keyboard and pointer events will be translated + * by the agent and sent to the internal clients according to + * events selected by the inferior windows. + */ + +static Mask defaultEventMask; + +static int lastEventSerial = 0; + +/* + * Used to mask the appropriate bits in + * the state reported by XkbStateNotify + * and XkbGetIndicatorState. + */ + +#define CAPSFLAG_IN_REPLY 1 +#define CAPSFLAG_IN_EVENT 2 +#define NUMFLAG_IN_EVENT 16 +#define NUMFLAG_IN_REPLY 2 + +CARD32 nxagentLastEventTime = 0; +CARD32 nxagentLastKeyPressTime = 0; +Time nxagentLastServerTime = 0; + +/* + * Used for storing windows that need to + * receive expose events from the agent. + */ + +#define nxagentExposeQueueHead nxagentExposeQueue.exposures[nxagentExposeQueue.start] + +ExposeQueue nxagentExposeQueue; + +RegionPtr nxagentRemoteExposeRegion = NULL; + +static void nxagentForwardRemoteExpose(void); + +static int nxagentClipAndSendExpose(WindowPtr pWin, void * ptr); + +/* + * This is from NXproperty.c. + */ + +int GetWindowProperty(WindowPtr pWin, Atom property, long longOffset, + long longLength, Bool delete, Atom type, + Atom *actualType, int *format, unsigned + long *nItems, unsigned long *bytesAfter, + unsigned char **propData); + +/* + * Associate a resource to a drawable and + * store the region affected by the split + * operation. + */ + +SplitResourceRec nxagentSplitResources[NXNumberOfResources]; + +/* + * Associate a resource to an unpack + * operation. + */ + +UnpackResourceRec nxagentUnpackResources[NXNumberOfResources]; + +/* + * We have to check these before launching + * the terminate dialog in rootless mode. + */ + +Bool nxagentLastWindowDestroyed = False; +Time nxagentLastWindowDestroyedTime = 0; + +/* + * Set this flag when an user input event + * is received. + */ + +int nxagentInputEvent = 0; + +int nxagentKeyDown = 0; + +void nxagentSwitchResizeMode(ScreenPtr pScreen); + +int nxagentCheckWindowConfiguration(XConfigureEvent* X); + +#define nxagentMonitoredDuplicate(keysym) \ + ((keysym) == XK_Left || (keysym) == XK_Up || \ + (keysym) == XK_Right || (keysym) == XK_Down || \ + (keysym) == XK_Page_Up || (keysym) == XK_Page_Down || \ + (keysym) == XK_Delete || (keysym) == XK_BackSpace) + +void nxagentRemoveDuplicatedKeys(XEvent *X); + +void ProcessInputEvents() +{ + #ifdef NX_DEBUG_INPUT + if (nxagentDebugInput == 1) + { + fprintf(stderr, "ProcessInputEvents: Processing input.\n"); + } + #endif + + mieqProcessInputEvents(); +} + +#ifdef DEBUG_TREE + +/* + * Print ID and name of window. + */ + +void nxagentRemoteWindowID(Window window, Bool newline) +{ +#ifdef NO_I18N + char *winName; +#else + XTextProperty tp; +#endif + + fprintf(stderr, "0x%lx", window); + + if (!window) + { + fprintf(stderr, " (none) "); + } + else + { + if (window == DefaultRootWindow(nxagentDisplay)) + { + fprintf(stderr, " (the root window) "); + } + +#ifdef NO_I18N + + if (!XFetchName(nxagentDisplay, window, &winName)) + { + fprintf(stderr, " (has no name) "); + } + else if (winName) + { + fprintf(stderr, " \"%s\" ", winName); + XFree(winName); + } + +#else + + if (XGetWMName(nxagentDisplay, window, &tp) != 0) + { + fprintf(stderr, " (has no name) "); + } + else if (tp.nitems > 0) + { + int count = 0; + int i, ret; + char **list = NULL; + + fprintf(stderr, " \""); + + ret = XmbTextPropertyToTextList(nxagentDisplay, &tp, &list, &count); + + if ((ret == Success || ret > 0) && list != NULL) + { + for (i = 0; i < count; i++) + { + fprintf(stderr, "%s", list[i]); + } + + XFreeStringList(list); + } + else + { + fprintf(stderr, "%s", tp.value); + } + + fprintf(stderr, "\" "); + } + +#endif + + else + { + fprintf(stderr, " (has no name) "); + } + } + + if (newline == TRUE) + { + fprintf(stderr, "\n"); + } + + return; +} + +/* + * Print info about remote window. + */ + +void nxagentRemoteWindowInfo(Window win, int indent, Bool newLine) +{ + XWindowAttributes attributes; + int i; + + if (XGetWindowAttributes(nxagentDisplay, win, &attributes) == 0) + { + return; + } + + for (i = 0; i < indent; i++) + { + fprintf(stderr, " "); + } + + fprintf(stderr, "x=%d y=%d width=%d height=%d class=%s map_state=%s " + "override_redirect=%s\n", attributes.x, attributes.y, + attributes.width, attributes.height, + (attributes.class == 0) ? "CopyFromParent" : + ((attributes.class == 1) ? "InputOutput" : "InputOnly"), + (attributes.map_state == 0) ? + "IsUnmapped" : (attributes.map_state == 1 ? + "IsUnviewable" : "IsViewable"), + (attributes.override_redirect == 0) ? + "No" : "Yes" ); + + if (newLine == TRUE) + { + fprintf(stderr, "\n"); + } +} + +/* + * Walk remote windows tree. + */ + +void nxagentRemoteWindowsTree(Window window, int level) +{ + int i, j; + unsigned long rootWin, parentWin; + unsigned int numChildren; + unsigned long *childList; + + if (!XQueryTree(nxagentDisplay, window, &rootWin, &parentWin, &childList, + &numChildren)) + { + fprintf(stderr, "nxagentRemoteWindowsTree - XQueryTree failed.\n"); + + return; + } + + if (level == 0) + { + fprintf(stderr, "\n"); + + fprintf(stderr, " Root Window ID: "); + nxagentRemoteWindowID(rootWin, TRUE); + + fprintf(stderr, " Parent window ID: "); + nxagentRemoteWindowID(parentWin, TRUE); + } + + if (level == 0 || numChildren > 0) + { + fprintf(stderr, " "); + + for (j = 0; j < level; j++) + { + fprintf(stderr, " "); + } + + fprintf(stderr, "%d child%s%s\n", numChildren, (numChildren == 1) ? "" : + "ren", (numChildren == 1) ? ":" : "."); + } + + for (i = (int) numChildren - 1; i >= 0; i--) + { + fprintf(stderr, " "); + + for (j = 0; j < level; j++) + { + fprintf(stderr, " "); + } + + nxagentRemoteWindowID(childList[i], TRUE); + + nxagentRemoteWindowInfo(childList[i], (level * 5) + 6, TRUE); + + nxagentRemoteWindowsTree(childList[i], level + 1); + } + + if (childList) + { + XFree((char *) childList); + } +} + +/* + * Print info about internal window. + */ + +void nxagentInternalWindowInfo(WindowPtr pWin, int indent, Bool newLine) +{ + int i; + int result; + unsigned long ulReturnItems; + unsigned long ulReturnBytesLeft; + Atom atomReturnType; + int iReturnFormat; + unsigned char *pszReturnData = NULL; + + fprintf(stderr, "Window ID=[0x%lx] Remote ID=[0x%lx] ", pWin -> drawable.id, + nxagentWindow(pWin)); + + result = GetWindowProperty(pWin, MakeAtom("WM_NAME", 7, False) , 0, + sizeof(CARD32), False, AnyPropertyType, + &atomReturnType, &iReturnFormat, + &ulReturnItems, &ulReturnBytesLeft, + &pszReturnData); + + fprintf(stderr, "Name: "); + + if (result == Success && pszReturnData != NULL) + { + pszReturnData[ulReturnItems] = '\0'; + + fprintf(stderr, "\"%s\"\n", (char *) pszReturnData); + } + else + { + fprintf(stderr, "%s\n", "( has no name )"); + } + + for (i = 0; i < indent; i++) + { + fprintf(stderr, " "); + } + + fprintf(stderr, "x=%d y=%d width=%d height=%d class=%s map_state=%s " + "override_redirect=%s", pWin -> drawable.x, pWin -> drawable.y, + pWin -> drawable.width, pWin -> drawable.height, + (pWin -> drawable.class == 0) ? "CopyFromParent" : + ((pWin -> drawable.class == 1) ? "InputOutput" : + "InputOnly"), + (pWin -> mapped == 0) ? + "IsUnmapped" : (pWin -> realized == 0 ? + "IsUnviewable" : "IsViewable"), + (pWin -> overrideRedirect == 0) ? + "No" : "Yes"); + + if (newLine == TRUE) + { + fprintf(stderr, "\n"); + } +} + +/* + * Walk internal windows tree. + */ + +void nxagentInternalWindowsTree(WindowPtr pWin, int indent) +{ + WindowPtr pChild; + int i; + + while (pWin) + { + pChild = pWin -> firstChild; + + for (i = 0; i < indent; i++) + { + fprintf(stderr, " "); + } + + nxagentInternalWindowInfo(pWin, indent, TRUE); + + fprintf(stderr, "\n"); + + nxagentInternalWindowsTree(pChild, indent + 4); + + pWin = pWin -> nextSib; + } +} + +#endif /* DEBUG_TREE */ + +void nxagentSwitchResizeMode(ScreenPtr pScreen) +{ + XSizeHints sizeHints; + + #ifdef DEBUG + fprintf(stderr, "nxagentSwitchResizeMode called.\n"); + #endif + + int desktopResize = nxagentOption(DesktopResize); + + nxagentChangeOption(DesktopResize, !desktopResize); + + sizeHints.flags = PMaxSize; + + if (nxagentOption(DesktopResize) == 0) + { + fprintf(stderr,"Info: Disabled desktop resize mode in agent.\n"); + + nxagentLaunchDialog(DIALOG_DISABLE_DESKTOP_RESIZE_MODE); + + if (nxagentOption(Fullscreen) == 0) + { + sizeHints.max_width = nxagentOption(RootWidth); + sizeHints.max_height = nxagentOption(RootHeight); + + XSetWMNormalHints(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], + &sizeHints); + } + } + else + { + fprintf(stderr,"Info: Enabled desktop resize mode in agent.\n"); + + nxagentLaunchDialog(DIALOG_ENABLE_DESKTOP_RESIZE_MODE); + + nxagentChangeScreenConfig(0, nxagentOption(Width), nxagentOption(Height), + 0, 0); + + if (nxagentOption(ClientOs) == ClientOsWinnt) + { + NXSetExposeParameters(nxagentDisplay, 0, 0, 0); + } + + sizeHints.max_width = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + sizeHints.max_height = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + + XSetWMNormalHints(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], + &sizeHints); + } +} + +void nxagentShadowSwitchResizeMode(ScreenPtr pScreen) +{ + XSizeHints sizeHints; + + int desktopResize = nxagentOption(DesktopResize); + + nxagentChangeOption(DesktopResize, !desktopResize); + + sizeHints.flags = PMaxSize; + + if (nxagentOption(DesktopResize) == 0) + { + nxagentShadowSetRatio(1.0, 1.0); + + nxagentShadowCreateMainWindow(screenInfo.screens[DefaultScreen(nxagentDisplay)], screenInfo.screens[0]->root, + screenInfo.screens[0]->root -> drawable.width, screenInfo.screens[0]->root -> drawable.height); + + sizeHints.max_width = nxagentOption(RootWidth); + sizeHints.max_height = nxagentOption(RootHeight); + + fprintf(stderr,"Info: Disabled resize mode in shadow agent.\n"); + } + else + { + nxagentShadowSetRatio(nxagentOption(Width) * 1.0 / + screenInfo.screens[0]->root -> drawable.width, + nxagentOption(Height) * 1.0 / + screenInfo.screens[0]->root -> drawable.height); + + nxagentShadowCreateMainWindow(screenInfo.screens[DefaultScreen(nxagentDisplay)], + screenInfo.screens[0]->root, screenInfo.screens[0]->root -> drawable.width, + screenInfo.screens[0]->root -> drawable.height); + + sizeHints.max_width = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + sizeHints.max_height = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + + fprintf(stderr,"Info: Enabled resize mode in shadow agent.\n"); + } + + XSetWMNormalHints(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], + &sizeHints); +} + +static void nxagentSwitchDeferMode(void) +{ + if (nxagentOption(DeferLevel) == 0) + { + nxagentChangeOption(DeferLevel, UNDEFINED); + + nxagentSetDeferLevel(); + } + else + { + nxagentChangeOption(DeferLevel, 0); + } + + if (nxagentOption(DeferLevel) != 0) + { + nxagentLaunchDialog(DIALOG_ENABLE_DEFER_MODE); + } + else + { + nxagentLaunchDialog(DIALOG_DISABLE_DEFER_MODE); + + nxagentForceSynchronization = 1; + } +} + +static Bool nxagentExposurePredicate(Display *display, XEvent *event, XPointer window) +{ + /* + * Handle both Expose and ProcessedExpose events. + * The latters are those not filtered by function + * nxagentWindowExposures(). + */ + + if (window) + { + return ((event -> type == Expose || event -> type == ProcessedExpose) && + event -> xexpose.window == *((Window *) window)); + } + else + { + return (event -> type == Expose || event -> type == ProcessedExpose); + } +} + +static int nxagentAnyEventPredicate(Display *display, XEvent *event, XPointer parameter) +{ + return 1; +} + +int nxagentInputEventPredicate(Display *display, XEvent *event, XPointer parameter) +{ + switch (event -> type) + { + case KeyPress: + case KeyRelease: + case ButtonPress: + case ButtonRelease: + { + return 1; + } + default: + { + return 0; + } + } +} + +void nxagentInitDefaultEventMask() +{ + Mask mask = NoEventMask; + + mask |= (StructureNotifyMask | VisibilityChangeMask); + + mask |= ExposureMask; + + mask |= NXAGENT_KEYBOARD_EVENT_MASK; + mask |= NXAGENT_POINTER_EVENT_MASK; + + defaultEventMask = mask; +} + +void nxagentGetDefaultEventMask(Mask *mask_return) +{ + *mask_return = defaultEventMask; +} + +void nxagentSetDefaultEventMask(Mask mask) +{ + defaultEventMask = mask; +} + +void nxagentGetEventMask(WindowPtr pWin, Mask *mask_return) +{ + Mask mask = NoEventMask; + + if (nxagentOption(Rootless)) + { + /* + * mask = pWin -> eventMask & + * ~(NXAGENT_KEYBOARD_EVENT_MASK | NXAGENT_POINTER_EVENT_MASK); + */ + + if (pWin -> drawable.class == InputOutput) + { + if (nxagentWindowTopLevel(pWin)) + { + mask = defaultEventMask; + } + else + { + mask = ExposureMask | VisibilityChangeMask | PointerMotionMask; + } + } + + mask |= PropertyChangeMask; + } + else if (pWin -> drawable.class != InputOnly) + { + mask = ExposureMask | VisibilityChangeMask; + } + + *mask_return = mask; +} + +static int nxagentChangeMapPrivate(WindowPtr pWin, void * ptr) +{ + if (pWin && nxagentWindowPriv(pWin)) + { + nxagentWindowPriv(pWin) -> isMapped = *((Bool *) ptr); + } + + return WT_WALKCHILDREN; +} + +static int nxagentChangeVisibilityPrivate(WindowPtr pWin, void * ptr) +{ + if (pWin && nxagentWindowPriv(pWin)) + { + nxagentWindowPriv(pWin) -> visibilityState = *((int *) ptr); + } + + return WT_WALKCHILDREN; +} + +void nxagentDispatchEvents(PredicateFuncPtr predicate) +{ + XEvent X; + xEvent x; + ScreenPtr pScreen = NULL; + + Bool minimize = False; + Bool startKbd = False; + Bool closeSession = False; + Bool switchFullscreen = False; + Bool switchAllScreens = False; + + /* + * Last entered top level window. + */ + + static WindowPtr nxagentLastEnteredTopLevelWindow = NULL; + + #ifdef BLOCKS + fprintf(stderr, "[Begin read]\n"); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new events with " + "predicate [%p].\n", predicate); + #endif + + if (nxagentRemoteExposeRegion == NULL) + { + nxagentInitRemoteExposeRegion(); + } + + /* + * We must read here, even if apparently there is + * nothing to read. The ioctl() based readable + * function, in fact, is often unable to detect a + * failure of the socket, in particular if the + * agent was connected to the proxy and the proxy + * is gone. Thus we must trust the wakeup handler + * that called us after the select(). + */ + + #ifdef TEST + + if (nxagentPendingEvents(nxagentDisplay) == 0) + { + fprintf(stderr, "nxagentDispatchEvents: PANIC! No event needs to be dispatched.\n"); + } + + #endif + + /* + * We want to process all the events already in + * the queue, plus any additional event that may + * be read from the network. If no event can be + * read, we want to continue handling our clients + * without flushing the output buffer. + */ + + while (nxagentCheckEvents(nxagentDisplay, &X, predicate != NULL ? predicate : + nxagentAnyEventPredicate, NULL) == 1) + { + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchEvents: Going to handle new event type [%d].\n", + X.type); + #endif + + /* + * Handle the incoming event. + */ + + switch (X.type) + { + #ifdef NXAGENT_CLIPBOARD + + case SelectionClear: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new SelectionClear event.\n"); + #endif + + nxagentClearSelection(&X); + + break; + } + case SelectionRequest: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new SelectionRequest event.\n"); + #endif + + nxagentRequestSelection(&X); + + break; + } + case SelectionNotify: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new SelectionNotify event.\n"); + #endif + + nxagentNotifySelection(&X); + + break; + } + + #endif /* NXAGENT_CLIPBOARD */ + + case PropertyNotify: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: PropertyNotify on " + "prop %d[%s] window %lx state %d\n", + (int)X.xproperty.atom, validateString(XGetAtomName(nxagentDisplay, X.xproperty.atom)), + X.xproperty.window, X.xproperty.state); + #endif + + nxagentHandlePropertyNotify(&X); + + break; + } + case KeyPress: + { + enum HandleEventResult result; + + KeySym keysym; + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new KeyPress event.\n"); + #endif + + nxagentInputEvent = 1; + + nxagentKeyDown++; + + nxagentHandleKeyPress(&X, &result); + + if (viewportLastKeyPressResult != result) + { + viewportInc = 1; + + viewportLastKeyPressResult = result; + } + + if (result != doNothing && result != doStartKbd) + { + pScreen = nxagentScreen(X.xkey.window); + } + + switch (result) + { + case doNothing: + { + break; + } + + #ifdef DEBUG_TREE + + case doDebugTree: + { + fprintf(stderr, "\n ========== nxagentRemoteWindowsTree ==========\n"); + nxagentRemoteWindowsTree(nxagentWindow(screenInfo.screens[0]->root), 0); + + fprintf(stderr, "\n========== nxagentInternalWindowsTree ==========\n"); + nxagentInternalWindowsTree(screenInfo.screens[0]->root, 0); + + break; + } + + #endif /* DEBUG_TREE */ + + case doCloseSession: + { + closeSession = TRUE; + + break; + } + case doMinimize: + { + minimize = TRUE; + + break; + } + case doStartKbd: + { + startKbd = TRUE; + + break; + } + case doSwitchFullscreen: + { + switchFullscreen = TRUE; + + break; + } + case doSwitchAllScreens: + { + switchAllScreens = TRUE; + + break; + } + case doViewportMoveUp: + { + nxagentMoveViewport(pScreen, 0, -nxagentOption(Height)); + + break; + } + case doViewportMoveDown: + { + nxagentMoveViewport(pScreen, 0, nxagentOption(Height)); + + break; + } + case doViewportMoveLeft: + { + nxagentMoveViewport(pScreen, -nxagentOption(Width), 0); + + break; + } + case doViewportMoveRight: + { + nxagentMoveViewport(pScreen, nxagentOption(Width), 0); + + break; + } + case doViewportUp: + { + nxagentMoveViewport(pScreen, 0, -nextinc(viewportInc)); + + break; + } + case doViewportDown: + { + nxagentMoveViewport(pScreen, 0, +nextinc(viewportInc)); + + break; + } + case doViewportLeft: + { + nxagentMoveViewport(pScreen, -nextinc(viewportInc), 0); + + break; + } + case doViewportRight: + { + nxagentMoveViewport(pScreen, +nextinc(viewportInc), 0); + + break; + } + case doSwitchResizeMode: + { + if (nxagentOption(Shadow) == 0) + { + if (nxagentNoDialogIsRunning) + { + nxagentSwitchResizeMode(pScreen); + } + } + else + { + nxagentShadowSwitchResizeMode(pScreen); + } + + break; + } + case doSwitchDeferMode: + { + if (nxagentNoDialogIsRunning) + { + nxagentSwitchDeferMode(); + } + + break; + } + default: + { + FatalError("nxagentDispatchEvent: handleKeyPress returned unknown value\n"); + + break; + } + } + + /* + * Elide multiple KeyPress/KeyRelease events of + * the same key and generate a single pair. This + * is intended to reduce the impact of the laten- + * cy on the key auto-repeat, handled by the re- + * mote X server. We may optionally do that only + * if the timestamps in the events show an exces- + * sive delay. + */ + + keysym = XKeycodeToKeysym(nxagentDisplay, X.xkey.keycode, 0); + + if (nxagentMonitoredDuplicate(keysym) == 1) + { + nxagentRemoveDuplicatedKeys(&X); + } + + if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow) == 1 && result == doNothing) + { + X.xkey.keycode = nxagentConvertKeycode(X.xkey.keycode); + + NXShadowEvent(nxagentDisplay, X); + } + + break; + } + case KeyRelease: + { + enum HandleEventResult result; + int sendKey = 0; + +/* +FIXME: If we don't flush the queue here, it could happen + that the inputInfo structure will not be up to date + when we perform the following check on down keys. +*/ + ProcessInputEvents(); + +/* +FIXME: Don't enqueue the KeyRelease event if the key was + not already pressed. This workaround avoids a fake + KeyPress is enqueued by the XKEYBOARD extension. + Another solution would be to let the events are + enqueued and to remove the KeyPress afterwards. +*/ + if (BitIsOn(inputInfo.keyboard -> key -> down, + nxagentConvertKeycode(X.xkey.keycode))) + { + sendKey = 1; + } + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new KeyRelease event.\n"); + #endif + + nxagentInputEvent = 1; + + nxagentKeyDown--; + + if (nxagentKeyDown <= 0) + { + nxagentKeyDown = 0; + } + + if (nxagentXkbState.Initialized == 0) + { + if (X.xkey.keycode == nxagentCapsLockKeycode) + { + nxagentXkbCapsTrap = 1; + } + else if (X.xkey.keycode == nxagentNumLockKeycode) + { + nxagentXkbNumTrap = 1; + } + + nxagentInitKeyboardState(); + + nxagentXkbCapsTrap = 0; + nxagentXkbNumTrap = 0; + } + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = KeyRelease; + x.u.u.detail = nxagentConvertKeycode(X.xkey.keycode); + x.u.keyButtonPointer.time = nxagentLastKeyPressTime + + (X.xkey.time - nxagentLastServerTime); + + nxagentLastServerTime = X.xkey.time; + + nxagentLastEventTime = GetTimeInMillis(); + + if (x.u.keyButtonPointer.time > nxagentLastEventTime) + { + x.u.keyButtonPointer.time = nxagentLastEventTime; + } + + if (!(nxagentCheckSpecialKeystroke(&X.xkey, &result)) && sendKey == 1) + { + mieqEnqueue(&x); + + CriticalOutputPending = 1; + + if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow)) + { + X.xkey.keycode = nxagentConvertKeycode(X.xkey.keycode); + + NXShadowEvent(nxagentDisplay, X); + } + } + + break; + } + case ButtonPress: + { + #ifdef NX_DEBUG_INPUT + if (nxagentDebugInput == 1) + { + fprintf(stderr, "nxagentDispatchEvents: Going to handle new ButtonPress event.\n"); + } + #endif + + nxagentInputEvent = 1; + + if (nxagentOption(Fullscreen)) + { + if (nxagentMagicPixelZone(X.xbutton.x, X.xbutton.y)) + { + pScreen = nxagentScreen(X.xbutton.window); + + minimize = True; + + break; + } + } + + if (nxagentIpaq && nxagentClients <= 0) + { + closeSession = TRUE; + } + + if (nxagentOption(DesktopResize) == False && + (X.xbutton.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask)) + { + /* + * Start viewport navigation mode. + */ + + int resource = nxagentWaitForResource(NXGetCollectGrabPointerResource, + nxagentCollectGrabPointerPredicate); + + ScreenPtr pScreen = nxagentScreen(X.xbutton.window); + viewportCursor = XCreateFontCursor(nxagentDisplay, XC_fleur); + + NXCollectGrabPointer(nxagentDisplay, resource, + nxagentDefaultWindows[pScreen -> myNum], True, + NXAGENT_POINTER_EVENT_MASK, GrabModeAsync, + GrabModeAsync, None, viewportCursor, + CurrentTime); + viewportLastX = X.xbutton.x; + viewportLastY = X.xbutton.y; + + break; + } + + if (!(nxagentOption(Fullscreen) && + X.xbutton.window == nxagentFullscreenWindow && + X.xbutton.subwindow == None)) + { + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = ButtonPress; + x.u.u.detail = inputInfo.pointer -> button -> map[nxagentReversePointerMap[X.xbutton.button]]; + x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis(); + + if (nxagentOption(Rootless)) + { + x.u.keyButtonPointer.rootX = X.xmotion.x_root; + x.u.keyButtonPointer.rootY = X.xmotion.y_root; + } + else + { + x.u.keyButtonPointer.rootX = X.xmotion.x - nxagentOption(RootX); + x.u.keyButtonPointer.rootY = X.xmotion.y - nxagentOption(RootY); + } + + #ifdef NX_DEBUG_INPUT + if (nxagentDebugInput == 1) + { + fprintf(stderr, "nxagentDispatchEvents: Adding ButtonPress event.\n"); + } + #endif + + mieqEnqueue(&x); + + CriticalOutputPending = 1; + } + + if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow)) + { + X.xbutton.x -= nxagentOption(RootX); + X.xbutton.y -= nxagentOption(RootY); + + if (nxagentOption(YRatio) != DONT_SCALE) + { + X.xbutton.x = (X.xbutton.x << PRECISION) / nxagentOption(YRatio); + } + + if (nxagentOption(XRatio) != DONT_SCALE) + { + X.xbutton.y = (X.xbutton.y << PRECISION) / nxagentOption(YRatio); + } + + NXShadowEvent(nxagentDisplay, X); + } + + break; + } + case ButtonRelease: + { + #ifdef NX_DEBUG_INPUT + if (nxagentDebugInput == 1) + { + fprintf(stderr, "nxagentDispatchEvents: Going to handle new ButtonRelease event.\n"); + } + #endif + + nxagentInputEvent = 1; + + if (viewportCursor) + { + /* + * Leave viewport navigation mode. + */ + + XUngrabPointer(nxagentDisplay, CurrentTime); + + XFreeCursor(nxagentDisplay, viewportCursor); + + viewportCursor = None; + } + + if (minimize != True) + { + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = ButtonRelease; + x.u.u.detail = inputInfo.pointer -> button -> map[nxagentReversePointerMap[X.xbutton.button]]; + x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis(); + + if (nxagentOption(Rootless)) + { + x.u.keyButtonPointer.rootX = X.xmotion.x_root; + x.u.keyButtonPointer.rootY = X.xmotion.y_root; + } + else + { + x.u.keyButtonPointer.rootX = X.xmotion.x - nxagentOption(RootX); + x.u.keyButtonPointer.rootY = X.xmotion.y - nxagentOption(RootY); + } + + #ifdef NX_DEBUG_INPUT + if (nxagentDebugInput == 1) + { + fprintf(stderr, "nxagentDispatchEvents: Adding ButtonRelease event.\n"); + } + #endif + + mieqEnqueue(&x); + + CriticalOutputPending = 1; + } + + if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow)) + { + X.xbutton.x -= nxagentOption(RootX); + X.xbutton.y -= nxagentOption(RootY); + + if (nxagentOption(XRatio) != DONT_SCALE) + { + X.xbutton.x = (X.xbutton.x << PRECISION) / nxagentOption(XRatio); + } + + if (nxagentOption(YRatio) != DONT_SCALE) + { + X.xbutton.y = (X.xbutton.y << PRECISION) / nxagentOption(YRatio); + } + + NXShadowEvent(nxagentDisplay, X); + } + + break; + } + case MotionNotify: + { + ScreenPtr pScreen = nxagentScreen(X.xmotion.window); + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new MotionNotify event.\n"); + #endif + + #ifdef NX_DEBUG_INPUT + if (nxagentDebugInput == 1) + { + fprintf(stderr, "nxagentDispatchEvents: Handling motion notify window [%ld] root [%ld] child [%ld].\n", + X.xmotion.window, X.xmotion.root, X.xmotion.subwindow); + + fprintf(stderr, "nxagentDispatchEvents: Pointer at [%d][%d] relative root [%d][%d].\n", + X.xmotion.x, X.xmotion.y, X.xmotion.x_root, X.xmotion.y_root); + } + #endif + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = MotionNotify; + + if (nxagentOption(Rootless)) + { + WindowPtr pWin = nxagentWindowPtr(X.xmotion.window); + + if (pWin) + { + nxagentLastEnteredWindow = pWin; + } + + if (nxagentPulldownDialogPid == 0 && nxagentLastEnteredTopLevelWindow && + (X.xmotion.y_root < nxagentLastEnteredTopLevelWindow -> drawable.y + 4)) + { + if (pWin && nxagentClientIsDialog(wClient(pWin)) == 0 && + nxagentLastEnteredTopLevelWindow -> parent == screenInfo.screens[0]->root && + nxagentLastEnteredTopLevelWindow -> overrideRedirect == False && + X.xmotion.x_root > (nxagentLastEnteredTopLevelWindow -> drawable.x + + (nxagentLastEnteredTopLevelWindow -> drawable.width >> 1) - 50) && + X.xmotion.x_root < (nxagentLastEnteredTopLevelWindow -> drawable.x + + (nxagentLastEnteredTopLevelWindow -> drawable.width >> 1) + 50) && + nxagentOption(Menu) == 1) + { + nxagentPulldownDialog(nxagentLastEnteredTopLevelWindow -> drawable.id); + } + } + + x.u.keyButtonPointer.rootX = X.xmotion.x_root; + x.u.keyButtonPointer.rootY = X.xmotion.y_root; + } + else + { + x.u.keyButtonPointer.rootX = X.xmotion.x - nxagentOption(RootX); + x.u.keyButtonPointer.rootY = X.xmotion.y - nxagentOption(RootY); + } + + x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis(); + + if (viewportCursor == None && + !(nxagentOption(Fullscreen) && + X.xmotion.window == nxagentDefaultWindows[pScreen -> myNum] + && X.xmotion.subwindow == None)) + { + #ifdef NX_DEBUG_INPUT + if (nxagentDebugInput == 1) + { + fprintf(stderr, "nxagentDispatchEvents: Adding motion event [%d, %d] to the queue.\n", + x.u.keyButtonPointer.rootX, x.u.keyButtonPointer.rootY); + } + #endif + + mieqEnqueue(&x); + } + + /* + * This test is more complicated and probably not necessary, compared + * to a simple check on viewportCursor. + * + * if (!nxagentOption(Fullscreen) && + * (X.xmotion.state & (ControlMask | Mod1Mask | Button1Mask)) == + * (ControlMask | Mod1Mask | Button1Mask)) + */ + + if (viewportCursor) + { + /* + * Pointer is in viewport navigation mode. + */ + + nxagentMoveViewport(pScreen, viewportLastX - X.xmotion.x, viewportLastY - X.xmotion.y); + + viewportLastX = X.xmotion.x; + viewportLastY = X.xmotion.y; + } + + if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow) && !viewportCursor) + { + X.xmotion.x -= nxagentOption(RootX); + X.xmotion.y -= nxagentOption(RootY); + + if (nxagentOption(XRatio) != DONT_SCALE) + { + X.xmotion.x = (X.xmotion.x << PRECISION) / nxagentOption(XRatio); + } + + if (nxagentOption(YRatio) != DONT_SCALE) + { + X.xmotion.y = (X.xmotion.y << PRECISION) / nxagentOption(YRatio); + } + + NXShadowEvent(nxagentDisplay, X); + } + + if (nxagentOption(Shadow) == 0) + { + nxagentInputEvent = 1; + } + + break; + } + case FocusIn: + { + WindowPtr pWin; + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new FocusIn event.\n"); + #endif + + /* + * Here we change the focus state in the agent. + * It looks like this is needed only for root- + * less mode at the present moment. + */ + + if (nxagentOption(Rootless) && + (pWin = nxagentWindowPtr(X.xfocus.window))) + { + SetInputFocus(serverClient, inputInfo.keyboard, pWin -> drawable.id, + RevertToPointerRoot, GetTimeInMillis(), False); + } + + if (X.xfocus.detail != NotifyInferior) + { + pScreen = nxagentScreen(X.xfocus.window); + + if (pScreen) + { + nxagentDirectInstallColormaps(pScreen); + } + } + + break; + } + case FocusOut: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new FocusOut event.\n"); + #endif + + if (X.xfocus.detail != NotifyInferior) + { + pScreen = nxagentScreen(X.xfocus.window); + + if (pScreen) + { + nxagentDirectUninstallColormaps(pScreen); + } + } + + #ifdef NXAGENT_FIXKEYS + + { + /* + * Force the keys all up when focus is lost. + */ + + int i, k; + int mask = 1; + CARD8 val; + + XEvent xM; + memset(&xM, 0, sizeof(XEvent)); + + for (i = 0; i < DOWN_LENGTH; i++) /* input.h */ + { + val = inputInfo.keyboard->key->down[i]; + + if (val != 0) + { + for (k = 0; k < 8; k++) + { + if (val & (mask << k)) + { + #ifdef NXAGENT_FIXKEYS_DEBUG + fprintf(stderr, "sending KeyRelease event for keycode: %x\n", + i * 8 + k); + #endif + + if (!nxagentOption(Rootless) || + inputInfo.keyboard->key->modifierMap[i * 8 + k]) + { + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = KeyRelease; + x.u.u.detail = i * 8 + k; + x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis(); + + if (nxagentOption(ViewOnly) == 0 && nxagentOption(Shadow)) + { + xM.type = KeyRelease; + xM.xkey.display = nxagentDisplay; + xM.xkey.type = KeyRelease; + xM.xkey.keycode = i * 8 + k; + xM.xkey.state = inputInfo.keyboard->key->state; + xM.xkey.time = GetTimeInMillis(); + NXShadowEvent(nxagentDisplay, xM); + } + + mieqEnqueue(&x); + } + } + } + } + } + + nxagentKeyDown = 0; + } + + #endif /* NXAGENT_FIXKEYS */ + + break; + } + case KeymapNotify: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new KeymapNotify event.\n"); + #endif + + break; + } + case EnterNotify: + { + WindowPtr pWin; + + WindowPtr pTLWin = NULL; + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new EnterNotify event.\n"); + #endif + + if (nxagentOption(Rootless)) + { + pWin = nxagentWindowPtr(X.xcrossing.window); + + if (pWin != NULL) + { + for (pTLWin = pWin; + pTLWin -> parent != pTLWin -> drawable.pScreen -> root; + pTLWin = pTLWin -> parent); + } + + if (pTLWin) + { + nxagentLastEnteredTopLevelWindow = pTLWin; + } + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: nxagentLastEnteredTopLevelWindow [%p].\n", + nxagentLastEnteredTopLevelWindow); + #endif + } + + if (nxagentOption(Rootless) && nxagentWMIsRunning && + (pWin = nxagentWindowPtr(X.xcrossing.window)) && + nxagentWindowTopLevel(pWin) && !pWin -> overrideRedirect && + (pWin -> drawable.x != X.xcrossing.x_root - X.xcrossing.x - pWin -> borderWidth || + pWin -> drawable.y != X.xcrossing.y_root - X.xcrossing.y - pWin -> borderWidth)) + { + /* + * This code is useful for finding the window + * position. It should be re-implemented by + * following the ICCCM 4.1.5 recommendations. + */ + + XID values[4]; + register XID *value = values; + Mask mask = 0; + ClientPtr pClient = wClient(pWin); + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: pWin -> drawable.x [%d] pWin -> drawable.y [%d].\n", + pWin -> drawable.x, pWin -> drawable.y); + #endif + + *value++ = (XID) (X.xcrossing.x_root - X.xcrossing.x - pWin -> borderWidth); + *value++ = (XID) (X.xcrossing.y_root - X.xcrossing.y - pWin -> borderWidth); + + /* + * nxagentWindowPriv(pWin)->x = (X.xcrossing.x_root - X.xcrossing.x); + * nxagentWindowPriv(pWin)->y = (X.xcrossing.y_root - X.xcrossing.y); + */ + + mask = CWX | CWY; + + nxagentScreenTrap = 1; + + ConfigureWindow(pWin, mask, (XID *) values, pClient); + + nxagentScreenTrap = 0; + } + + if (nxagentOption(Fullscreen) == 1 && + X.xcrossing.window == nxagentFullscreenWindow && + X.xcrossing.detail != NotifyInferior) + { + nxagentGrabPointerAndKeyboard(&X); + } + + if (X.xcrossing.detail != NotifyInferior) + { + pScreen = nxagentScreen(X.xcrossing.window); + + if (pScreen) + { + NewCurrentScreen(pScreen, X.xcrossing.x, X.xcrossing.y); + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = MotionNotify; + + if (nxagentOption(Rootless)) + { + nxagentLastEnteredWindow = nxagentWindowPtr(X.xcrossing.window); + x.u.keyButtonPointer.rootX = X.xcrossing.x_root; + x.u.keyButtonPointer.rootY = X.xcrossing.y_root; + } + else + { + x.u.keyButtonPointer.rootX = X.xcrossing.x - nxagentOption(RootX); + x.u.keyButtonPointer.rootY = X.xcrossing.y - nxagentOption(RootY); + } + + x.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis(); + + mieqEnqueue(&x); + + nxagentDirectInstallColormaps(pScreen); + } + } + + nxagentInputEvent = 1; + + break; + } + case LeaveNotify: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new LeaveNotify event.\n"); + #endif + + if (nxagentOption(Rootless) && X.xcrossing.mode == NotifyNormal && + X.xcrossing.detail != NotifyInferior) + { + nxagentLastEnteredWindow = NULL; + } + + if (X.xcrossing.window == nxagentDefaultWindows[0] && + X.xcrossing.detail != NotifyInferior && + X.xcrossing.mode == NotifyNormal) + { + nxagentUngrabPointerAndKeyboard(&X); + } + + if (X.xcrossing.detail != NotifyInferior) + { + pScreen = nxagentScreen(X.xcrossing.window); + + if (pScreen) + { + nxagentDirectUninstallColormaps(pScreen); + } + } + + nxagentInputEvent = 1; + + break; + } + case DestroyNotify: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new DestroyNotify event.\n"); + #endif + + if (nxagentParentWindow != (Window) 0 && + X.xdestroywindow.window == nxagentParentWindow) + { + fprintf(stderr, "Warning: Unhandled destroy notify event received in agent.\n"); + } + + break; + } + case ClientMessage: + { + enum HandleEventResult result; + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new ClientMessage event.\n"); + #endif + + nxagentHandleClientMessageEvent(&X, &result); + + if (result == doCloseSession) + { + closeSession = TRUE; + } + + break; + } + case VisibilityNotify: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new VisibilityNotify event.\n"); + #endif + + if (X.xvisibility.window != nxagentDefaultWindows[0]) + { + Window window = X.xvisibility.window; + + WindowPtr pWin = nxagentWindowPtr(window); + + if (pWin && nxagentWindowPriv(pWin)) + { + if (nxagentWindowPriv(pWin) -> visibilityState != X.xvisibility.state) + { + int value = X.xvisibility.state; + + if (nxagentOption(Rootless) == 1) + { + TraverseTree(pWin, nxagentChangeVisibilityPrivate, &value); + } + else + { + nxagentChangeVisibilityPrivate(pWin, &value); + } + } + } + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Suppressing visibility notify on window [%lx].\n", + X.xvisibility.window); + #endif + + break; + } + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Visibility notify state is [%d] with previous [%d].\n", + X.xvisibility.state, nxagentVisibility); + #endif + + nxagentVisibility = X.xvisibility.state; + + break; + } + case Expose: + { + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchEvents: Going to handle new Expose event.\n"); + + fprintf(stderr, "nxagentDispatchEvents: WARNING! Received Expose event " + "for drawable [%lx] geometry [%d, %d, %d, %d] count [%d].\n", + X.xexpose.window, X.xexpose.x, X.xexpose.y, X.xexpose.width, + X.xexpose.height, X.xexpose.count); + #endif + + nxagentHandleExposeEvent(&X); + + break; + } + case GraphicsExpose: + { + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchEvents: Going to handle new GraphicsExpose event.\n"); + + fprintf(stderr, "nxagentDispatchEvents: WARNING! Received GraphicsExpose event " + "for drawable [%lx] geometry [%d, %d, %d, %d] count [%d].\n", + X.xgraphicsexpose.drawable, X.xgraphicsexpose.x, X.xgraphicsexpose.y, + X.xgraphicsexpose.width, X.xgraphicsexpose.height, + X.xgraphicsexpose.count); + #endif + + nxagentHandleGraphicsExposeEvent(&X); + + break; + } + case NoExpose: + { + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchEvents: Going to handle new NoExpose event.\n"); + + fprintf(stderr, "nxagentDispatchEvents: WARNING! Received NoExpose event for " + "drawable [%lx].\n", X.xnoexpose.drawable); + #endif + + break; + } + case CirculateNotify: + { + /* + * WindowPtr pWin; + * WindowPtr pSib; + * ClientPtr pClient; + + * XID values[2]; + * register XID *value = values; + * Mask mask = 0; + */ + + #ifdef WARNING + fprintf(stderr, "nxagentDispatchEvents: Going to handle new CirculateNotify event.\n"); + #endif + + /* + * FIXME: Do we need this? + * + * pWin = nxagentWindowPtr(X.xcirculate.window); + * + * if (!pWin) + * { + * pWin = nxagentRootlessTopLevelWindow(X.xcirculate.window); + * } + * + * if (!pWin) + * { + * break; + * } + * + * XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + * &root_return, &parent_return, &children_return, &nchildren_return); + * + * nxagentRootlessRestack(children_return, nchildren_return); + */ + + break; + } + case ConfigureNotify: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new ConfigureNotify event.\n"); + #endif + + if (nxagentConfiguredSynchroWindow == X.xconfigure.window) + { + if (nxagentExposeQueue.exposures[nxagentExposeQueue.start].serial != X.xconfigure.x) + { + #ifdef WARNING + if (nxagentVerbose == 1) + { + fprintf(stderr, "nxagentDispatchEvents: Requested ConfigureNotify changes didn't take place.\n"); + } + #endif + } + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Received ConfigureNotify and going to call " + "nxagentSynchronizeExpose.\n"); + #endif + + nxagentSynchronizeExpose(); + + break; + } + + nxagentHandleConfigureNotify(&X); + + break; + } + case GravityNotify: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new GravityNotify event.\n"); + #endif + + break; + } + case ReparentNotify: + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new ReparentNotify event.\n"); + #endif + + nxagentHandleReparentNotify(&X); + + break; + } + case UnmapNotify: + { + WindowPtr pWin; + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new UnmapNotify event.\n"); + #endif + + if (nxagentOption(Rootless) == 1) + { + if ((pWin = nxagentRootlessTopLevelWindow(X.xunmap.window)) != NULL || + ((pWin = nxagentWindowPtr(X.xunmap.window)) != NULL && + nxagentWindowTopLevel(pWin) == 1)) + { + nxagentScreenTrap = 1; + + UnmapWindow(pWin, False); + + nxagentScreenTrap = 0; + } + } + + if (nxagentUseNXTrans == 1 && nxagentOption(Rootless) == 0 && + nxagentOption(Nested) == 0 && + X.xmap.window != nxagentIconWindow) + { + nxagentVisibility = VisibilityFullyObscured; + } + + break; + } + case MapNotify: + { + WindowPtr pWin; + ClientPtr pClient; + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Going to handle new MapNotify event.\n"); + #endif + + if (nxagentOption(Rootless) == 1) + { + Bool value = 1; + + if ((pWin = nxagentRootlessTopLevelWindow(X.xmap.window)) != NULL || + ((pWin = nxagentWindowPtr(X.xmap.window)) != NULL && + nxagentWindowTopLevel(pWin) == 1)) + { + pClient = wClient(pWin); + + nxagentScreenTrap = 1; + + MapWindow(pWin, pClient); + + nxagentScreenTrap = 0; + } + + if (pWin != NULL) + { + TraverseTree(pWin, nxagentChangeMapPrivate, &value); + } + } + + if (nxagentOption(AllScreens) == 1) + { + if (X.xmap.window == nxagentIconWindow) + { + pScreen = nxagentScreen(X.xmap.window); + nxagentMaximizeToFullScreen(pScreen); + } + } + + if (nxagentOption(Fullscreen) == 1) + { + nxagentVisibility = VisibilityUnobscured; + nxagentVisibilityStop = False; + nxagentVisibilityTimeout = GetTimeInMillis() + 2000; + } + + break; + } + case MappingNotify: + { + XMappingEvent *mappingEvent = (XMappingEvent *) &X; + + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchEvents: WARNING! Going to handle new MappingNotify event.\n"); + #endif + + if (mappingEvent -> request == MappingPointer) + { + nxagentInitPointerMap(); + } + + break; + } + default: + { + /* + * Let's check if this is a XKB + * state modification event. + */ + + if (nxagentHandleKeyboardEvent(&X) == 0 && nxagentHandleXFixesSelectionNotify(&X) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: WARNING! Unhandled event code [%d].\n", + X.type); + #endif + } + + break; + } + + } /* End of switch (X.type) */ + + if (X.xany.serial < lastEventSerial) + { + /* + * Start over. + */ + + nxagentDeleteStaticResizedWindow(0); + } + else + { + nxagentDeleteStaticResizedWindow(X.xany.serial - 1); + } + + lastEventSerial = X.xany.serial; + + } /* End of while (...) */ + + /* + * Send the exposed regions to the clients. + */ + + nxagentForwardRemoteExpose(); + + /* + * Handle the agent window's changes. + */ + + if (closeSession) + { + if (nxagentOption(Persistent)) + { + if (nxagentNoDialogIsRunning) + { + nxagentLaunchDialog(DIALOG_SUSPEND_SESSION); + } + } + else + { + if (nxagentNoDialogIsRunning) + { + nxagentLaunchDialog(DIALOG_KILL_SESSION); + } + } + } + + if (minimize) + { + nxagentWMDetect(); + + if (nxagentWMIsRunning) + { + if (nxagentOption(AllScreens)) + { + nxagentMinimizeFromFullScreen(pScreen); + } + else + { + XIconifyWindow(nxagentDisplay, nxagentDefaultWindows[0], + DefaultScreen(nxagentDisplay)); + } + } + } + + if (switchFullscreen) + { + if (nxagentOption(AllScreens) == 1 && nxagentOption(Fullscreen) == 1) + { + nxagentSwitchAllScreens(pScreen, 0); + } + else + { + nxagentSwitchFullscreen(pScreen, !nxagentOption(Fullscreen)); + } + } + + if (switchAllScreens) + { + if (nxagentOption(AllScreens) == 0 && nxagentOption(Fullscreen) == 1) + { + nxagentSwitchFullscreen(pScreen, 0); + } + else + { + nxagentSwitchAllScreens(pScreen, !nxagentOption(AllScreens)); + } + } + + if (startKbd) + { + if (xkbdRunning) + { + #ifdef NXAGENT_XKBD_DEBUG + fprintf(stderr, "Events: nxkbd now is NOT running: %d, %d\n", + X.xkey.keycode, escapecode); + #endif + + xkbdRunning = False; + + kill(pidkbd, 9); + } + else + { + char kbddisplay[6]; + char *kbdargs[6]; + + strcpy(kbddisplay,":"); + strncat(kbddisplay, display, 4); + + kbdargs[0] = "nxkbd"; + kbdargs[1] = "-geometry"; + kbdargs[2] = "240x70+0+250"; + kbdargs[3] = "-display"; + kbdargs[4] = kbddisplay; + kbdargs[5] = NULL; + + switch (pidkbd = fork()) + { + case 0: + { + execvp(kbdargs[0], kbdargs); + + #ifdef NXAGENT_XKBD_DEBUG + fprintf(stderr, "Events: The execvp of nxkbd process failed.\n"); + #endif + + exit(1); + + break; + } + case -1: + { + #ifdef NXAGENT_XKBD_DEBUG + fprintf(stderr, "Events: Can't fork to run the nxkbd process.\n"); + #endif + + break; + } + default: + { + break; + } + } + + #ifdef NXAGENT_XKBD_DEBUG + fprintf(stderr, "Events: The nxkbd process now running with [%d][%d].\n", + X.xkey.keycode, escapecode); + #endif + + xkbdRunning = True; + } + } + + #ifdef BLOCKS + fprintf(stderr, "[End read]\n"); + #endif + + /* + * Let the underlying X server code + * process the input events. + */ + + #ifdef BLOCKS + fprintf(stderr, "[Begin events]\n"); + #endif + + ProcessInputEvents(); + + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Output pending flag is [%d] critical [%d].\n", + NewOutputPending, CriticalOutputPending); + #endif + + /* + * Write the events to our clients. We may + * flush only in the case of critical output + * but this doesn't seem beneficial. + * + * if (CriticalOutputPending == 1) + * { + * FlushAllOutput(); + * } + */ + + if (NewOutputPending == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentDispatchEvents: Flushed the processed events to clients.\n"); + #endif + + FlushAllOutput(); + } + + #ifdef TEST + + if (nxagentPendingEvents(nxagentDisplay) > 0) + { + fprintf(stderr, "nxagentDispatchEvents: WARNING! More events need to be dispatched.\n"); + } + + #endif + + #ifdef BLOCKS + fprintf(stderr, "[End events]\n"); + #endif +} + +/* + * Functions providing the ad-hoc handling + * of the remote X events. + */ + +int nxagentHandleKeyPress(XEvent *X, enum HandleEventResult *result) +{ + xEvent x; + + if (nxagentXkbState.Initialized == 0) + { + if (X -> xkey.keycode == nxagentCapsLockKeycode) + { + nxagentXkbCapsTrap = 1; + } + else if (X -> xkey.keycode == nxagentNumLockKeycode) + { + nxagentXkbNumTrap = 1; + } + + nxagentInitKeyboardState(); + + nxagentXkbCapsTrap = 0; + nxagentXkbNumTrap = 0; + } + + if (nxagentCheckSpecialKeystroke(&X -> xkey, result)) + { + return 1; + } + + if (X -> xkey.keycode == nxagentCapsLockKeycode) + { + nxagentXkbState.Caps = (~nxagentXkbState.Caps & 1); + } + else if (X -> xkey.keycode == nxagentNumLockKeycode) + { + nxagentXkbState.Num = (~nxagentXkbState.Num & 1); + } + + nxagentLastEventTime = nxagentLastKeyPressTime = GetTimeInMillis(); + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = KeyPress; + x.u.u.detail = nxagentConvertKeycode(X -> xkey.keycode); + x.u.keyButtonPointer.time = nxagentLastKeyPressTime; + + nxagentLastServerTime = X -> xkey.time; + + mieqEnqueue(&x); + + CriticalOutputPending = 1; + + return 1; +} + +int nxagentHandlePropertyNotify(XEvent *X) +{ + int resource; + + if (nxagentOption(Rootless) && !nxagentNotifyMatchChangeProperty((XPropertyEvent *) X)) + { + #ifdef TEST + fprintf(stderr, "nxagentHandlePropertyNotify: Property %ld on window %lx.\n", + X -> xproperty.atom, X -> xproperty.window); + #endif + + if (nxagentWindowPtr(X -> xproperty.window) != NULL) + { + resource = NXGetCollectPropertyResource(nxagentDisplay); + + if (resource == -1) + { + #ifdef WARNING + fprintf(stderr, "nxagentHandlePropertyNotify: WARNING! Asynchronous get property queue is full.\n"); + #endif + + return 0; + } + + NXCollectProperty(nxagentDisplay, resource, + X -> xproperty.window, X -> xproperty.atom, 0, + MAX_RETRIEVED_PROPERTY_SIZE, False, AnyPropertyType); + + nxagentPropertyRequests[resource].window = X -> xproperty.window; + nxagentPropertyRequests[resource].property = X -> xproperty.atom; + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentHandlePropertyNotify: Failed to look up remote window property.\n"); + } + #endif + } + + return 1; +} + +int nxagentHandleExposeEvent(XEvent *X) +{ + WindowPtr pWin = NULL; + Window window = None; + + RegionRec sum; + RegionRec add; + BoxRec box; + int index = 0; + int overlap = 0; + + StaticResizedWindowStruct *resizedWinPtr = NULL; + + #ifdef DEBUG + fprintf(stderr, "nxagentHandleExposeEvent: Checking remote expose events.\n"); + + fprintf(stderr, "nxagentHandleExposeEvent: Looking for window id [%ld].\n", + X -> xexpose.window); + #endif + + window = X -> xexpose.window; + + pWin = nxagentWindowPtr(window); + + if (pWin != NULL) + { + RegionInit(&sum, (BoxRec *) NULL, 1); +/* +FIXME: This can be maybe optimized by consuming the + events that do not match the predicate. +*/ + do + { + #ifdef DEBUG + fprintf(stderr, "nxagentHandleExposeEvent: Adding event for window id [%ld].\n", + X -> xexpose.window); + #endif + + box.x1 = pWin -> drawable.x + wBorderWidth(pWin) + X -> xexpose.x; + box.y1 = pWin -> drawable.y + wBorderWidth(pWin) + X -> xexpose.y; + + resizedWinPtr = nxagentFindStaticResizedWindow(X -> xany.serial); + + while (resizedWinPtr) + { + if (resizedWinPtr -> pWin == pWin) + { + box.x1 += resizedWinPtr -> offX; + box.y1 += resizedWinPtr -> offY; + } + + resizedWinPtr = resizedWinPtr -> prev; + } + + box.x2 = box.x1 + X -> xexpose.width; + box.y2 = box.y1 + X -> xexpose.height; + + RegionInit(&add, &box, 1); + + RegionAppend(&sum, &add); + + RegionUninit(&add); + + if (X -> xexpose.count == 0) + { + break; + } + } + while (nxagentCheckEvents(nxagentDisplay, X, nxagentExposurePredicate, + (XPointer) &window) == 1); + + RegionValidate(&sum, &overlap); + + RegionIntersect(&sum, &sum, + &pWin->drawable.pScreen->root->winSize); + + #ifdef DEBUG + fprintf(stderr, "nxagentHandleExposeEvent: Sending events for window id [%ld].\n", + X -> xexpose.window); + #endif + + /* + * If the agent has already sent auto-generated expose, + * save received exposes for later processing. + */ + + index = nxagentLookupByWindow(pWin); + + if (index == -1) + { + miWindowExposures(pWin, &sum, NullRegion); + } + else + { + RegionTranslate(&sum, -pWin -> drawable.x, -pWin -> drawable.y); + + if (nxagentExposeQueue.exposures[index].remoteRegion == NullRegion) + { + nxagentExposeQueue.exposures[index].remoteRegion = RegionCreate(NULL, 1); + } + + RegionUnion(nxagentExposeQueue.exposures[index].remoteRegion, + nxagentExposeQueue.exposures[index].remoteRegion, &sum); + + #ifdef TEST + fprintf(stderr, "nxagentHandleExposeEvent: Added region for window [%ld] to position [%d].\n", + nxagentWindow(pWin), index); + #endif + + if (X -> xexpose.count == 0) + { + nxagentExposeQueue.exposures[index].remoteRegionIsCompleted = True; + } + else + { + nxagentExposeQueue.exposures[index].remoteRegionIsCompleted = False; + } + } + + if (nxagentRootTileWindow != NULL) + { + if (nxagentWindowPriv(nxagentRootTileWindow) -> window == nxagentWindowPriv(pWin) -> window && + nxagentSplashCount == 1 && X -> xexpose.count == 0) + { + #ifdef DEBUG + fprintf(stderr, "nxagentHandleExposeEvent: Clearing root tile window id [%ld].\n", + nxagentWindowPriv(nxagentRootTileWindow) -> window); + #endif + + XClearWindow(nxagentDisplay, nxagentWindowPriv(nxagentRootTileWindow) -> window); + } + } + + RegionUninit(&sum); + } + + return 1; +} + +int nxagentHandleGraphicsExposeEvent(XEvent *X) +{ + /* + * Send an expose event to client, instead of graphics + * expose. If target drawable is a backing pixmap, send + * expose event for the saved window, else do nothing. + */ + + RegionPtr exposeRegion; + BoxRec rect; + WindowPtr pWin; + StoringPixmapPtr pStoringPixmapRec = NULL; + miBSWindowPtr pBSwindow = NULL; + int drawableType; + + pWin = nxagentWindowPtr(X -> xgraphicsexpose.drawable); + + if (pWin != NULL) + { + drawableType = DRAWABLE_WINDOW; + } + else + { + drawableType = DRAWABLE_PIXMAP; + } + + if (drawableType == DRAWABLE_PIXMAP) + { + pStoringPixmapRec = nxagentFindItemBSPixmapList(X -> xgraphicsexpose.drawable); + + if (pStoringPixmapRec == NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleGraphicsExposeEvent: WARNING! Storing pixmap not found.\n"); + #endif + + return 1; + } + + pBSwindow = (miBSWindowPtr) pStoringPixmapRec -> pSavedWindow -> backStorage; + + if (pBSwindow == NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleGraphicsExposeEvent: WARNING! Back storage not found.\n"); + #endif + + return 1; + } + + pWin = pStoringPixmapRec -> pSavedWindow; + } + + /* + * Rectangle affected by GraphicsExpose + * event. + */ + + rect.x1 = X -> xgraphicsexpose.x; + rect.y1 = X -> xgraphicsexpose.y; + rect.x2 = rect.x1 + X -> xgraphicsexpose.width; + rect.y2 = rect.y1 + X -> xgraphicsexpose.height; + + exposeRegion = RegionCreate(&rect, 0); + + if (drawableType == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleGraphicsExposeEvent: Handling GraphicsExpose event on pixmap with id" + " [%lu].\n", X -> xgraphicsexpose.drawable); + #endif + + /* + * The exposeRegion coordinates are relative + * to the pixmap to which GraphicsExpose + * event refers. But the BS coordinates of + * the savedRegion are relative to the + * window. + */ + + RegionTranslate(exposeRegion, pStoringPixmapRec -> backingStoreX, + pStoringPixmapRec -> backingStoreY); + + /* + * We remove from SavedRegion the part + * affected by the GraphicsExpose event. + */ + + RegionSubtract(&(pBSwindow -> SavedRegion), &(pBSwindow -> SavedRegion), + exposeRegion); + } + + /* + * Store the exposeRegion in order to send + * the expose event later. The coordinates + * must be relative to the screen. + */ + + RegionTranslate(exposeRegion, pWin -> drawable.x, pWin -> drawable.y); + + RegionUnion(nxagentRemoteExposeRegion, nxagentRemoteExposeRegion, exposeRegion); + + RegionDestroy(exposeRegion); + + return 1; +} + +int nxagentHandleClientMessageEvent(XEvent *X, enum HandleEventResult *result) +{ + WindowPtr pWin; + + *result = doNothing; + + #ifdef TEST + fprintf(stderr, "nxagentHandleClientMessageEvent: ClientMessage event window [%ld] with " + "type [%ld] format [%d].\n", X -> xclient.window, X -> xclient.message_type, + X -> xclient.format); + #endif + + /* + * If window is 0, message_type is 0 and format is + * 32 then we assume event is coming from proxy. + */ + + if (X -> xclient.window == 0 && + X -> xclient.message_type == 0 && + X -> xclient.format == 32) + { + nxagentHandleProxyEvent(X); + + return 1; + } + + if (nxagentOption(Rootless)) + { + Atom message_type = nxagentRemoteToLocalAtom(X -> xclient.message_type); + + if (!ValidAtom(message_type)) + { + #ifdef WARNING + fprintf(stderr, "nxagentHandleClientMessageEvent: WARNING Invalid type in client message.\n"); + #endif + + return 0; + } + + pWin = nxagentWindowPtr(X -> xclient.window); + + if (pWin == NULL) + { + #ifdef WARNING + fprintf(stderr, "WARNING: Invalid window in ClientMessage.\n"); + #endif + + return 0; + } + + if (message_type == MakeAtom("WM_PROTOCOLS", strlen("WM_PROTOCOLS"), False)) + { + #ifdef TEST + char *message_data; + #endif + + xEvent x; + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = ClientMessage; + x.u.u.detail = X -> xclient.format; + + x.u.clientMessage.window = pWin -> drawable.id; + x.u.clientMessage.u.l.type = message_type; + x.u.clientMessage.u.l.longs0 = nxagentRemoteToLocalAtom(X -> xclient.data.l[0]); + x.u.clientMessage.u.l.longs1 = GetTimeInMillis(); + + if (!ValidAtom(x.u.clientMessage.u.l.longs0)) + { + #ifdef WARNING + fprintf(stderr, "nxagentHandleClientMessageEvent: WARNING Invalid value in client message " + "of type WM_PROTOCOLS.\n"); + #endif + + return 0; + } + #ifdef TEST + else + { + message_data = validateString(NameForAtom(x.u.clientMessage.u.l.longs0)); + } + + fprintf(stderr, "nxagentHandleClientMessageEvent: Sent client message of type WM_PROTOCOLS " + "and value [%s].\n", message_data); + #endif + + TryClientEvents(wClient(pWin), &x, 1, 1, 1, 0); + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentHandleClientMessageEvent: Ignored message type %ld [%s].\n", + (long int) message_type, validateString(NameForAtom(message_type))); + #endif + + return 0; + } + + return 1; + } + + if (X -> xclient.message_type == nxagentAtoms[1]) /* WM_PROTOCOLS */ + { + Atom deleteWMatom, wmAtom; + + wmAtom = (Atom) X -> xclient.data.l[0]; + + deleteWMatom = nxagentAtoms[2]; /* WM_DELETE_WINDOW */ + + if (wmAtom == deleteWMatom) + { + if (nxagentOnce && (nxagentClients == 0)) + { + GiveUp(0); + } + else + { + #ifdef TEST + fprintf(stderr, "Events: WM_DELETE_WINDOW arrived Atom = %ld.\n", wmAtom); + #endif + + if (X -> xclient.window == nxagentIconWindow) + { + XMapRaised(nxagentDisplay, nxagentFullscreenWindow); + + XIconifyWindow(nxagentDisplay, nxagentIconWindow, + DefaultScreen(nxagentDisplay)); + + } + + if (X -> xclient.window == (nxagentOption(Fullscreen) ? + nxagentIconWindow : nxagentDefaultWindows[0]) || + nxagentWMIsRunning == 0) + { + *result = doCloseSession; + } + } + } + } + + return 1; +} + +int nxagentHandleKeyboardEvent(XEvent *X) +{ + XkbEvent *xkbev = (XkbEvent *) X; + + #ifdef TEST + fprintf(stderr, "nxagentHandleKeyboardEvent: Handling event with caps [%d] num [%d] locked [%d].\n", + nxagentXkbState.Caps, nxagentXkbState.Num, nxagentXkbState.Locked); + #endif + + if (xkbev -> type == nxagentXkbInfo.EventBase + XkbEventCode && + xkbev -> any.xkb_type == XkbStateNotify) + { + nxagentXkbState.Locked = xkbev -> state.locked_mods; + + #ifdef TEST + fprintf(stderr, "nxagentHandleKeyboardEvent: Updated XKB locked modifier bits to [%x].\n", + nxagentXkbState.Locked); + #endif + + nxagentXkbState.Initialized = 1; + + if (nxagentXkbState.Caps == 0 && + (nxagentXkbState.Locked & CAPSFLAG_IN_EVENT)) + { + nxagentXkbState.Caps = 1; + + #ifdef TEST + fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [66] to engage capslock.\n"); + #endif + + if (!nxagentXkbCapsTrap) + { + nxagentSendFakeKey(66); + } + } + + if (nxagentXkbState.Caps == 1 && + !(nxagentXkbState.Locked & CAPSFLAG_IN_EVENT)) + { + nxagentXkbState.Caps = 0; + + #ifdef TEST + fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [66] to release capslock.\n"); + #endif + + nxagentSendFakeKey(66); + } + + if (nxagentXkbState.Caps == 0 && + !(nxagentXkbState.Locked & CAPSFLAG_IN_EVENT) && + nxagentXkbCapsTrap) + { + + #ifdef TEST + fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [66] to release capslock.\n"); + #endif + + nxagentSendFakeKey(66); + } + + if (nxagentXkbState.Num == 0 && + (nxagentXkbState.Locked & NUMFLAG_IN_EVENT)) + { + nxagentXkbState.Num = 1; + + #ifdef TEST + fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [77] to engage numlock.\n"); + #endif + + if (!nxagentXkbNumTrap) + { + nxagentSendFakeKey(77); + } + } + + if (nxagentXkbState.Num == 1 && + !(nxagentXkbState.Locked & NUMFLAG_IN_EVENT)) + { + nxagentXkbState.Num = 0; + + #ifdef TEST + fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [77] to release numlock.\n"); + #endif + + nxagentSendFakeKey(77); + } + + if (nxagentXkbState.Num == 0 && + !(nxagentXkbState.Locked & NUMFLAG_IN_EVENT) && + nxagentXkbNumTrap) + { + + #ifdef TEST + fprintf(stderr, "nxagentHandleKeyboardEvent: Sending fake key [77] to release numlock.\n"); + #endif + + nxagentSendFakeKey(77); + } + + return 1; + } + + return 0; +} + +int nxagentHandleXFixesSelectionNotify(XEvent *X) +{ + int i; + Atom local; + + XFixesSelectionEvent *xfixesEvent = (XFixesSelectionEvent *) X; + + if (nxagentXFixesInfo.Initialized == 0 || + xfixesEvent -> type != (nxagentXFixesInfo.EventBase + XFixesSelectionNotify)) + return 0; + + #ifdef TEST + fprintf(stderr, "nxagentHandleXFixesSelectionNotify: Handling event.\n"); + #endif + + local = nxagentRemoteToLocalAtom(xfixesEvent -> xfixesselection.selection); + + if (SelectionCallback) + { + i = 0; + + while ((i < NumCurrentSelections) && + CurrentSelections[i].selection != local) + i++; + + if (i < NumCurrentSelections) + { + SelectionInfoRec info; + + if (CurrentSelections[i].client != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleXFixesSelectionNotify: Do nothing.\n"); + #endif + + return 1; + } + + #ifdef TEST + fprintf(stderr, "nxagentHandleXFixesSelectionNotify: Calling callbacks for %d [%s] selection.\n", + CurrentSelections[i].selection, NameForAtom(CurrentSelections[i].selection)); + #endif + + #ifdef DEBUG + fprintf(stderr, "nxagentHandleXFixesSelectionNotify: Subtype "); + + switch (xfixesEvent -> xfixesselection.subtype) + { + case SelectionSetOwner: + fprintf(stderr, "SelectionSetOwner.\n"); + break; + case SelectionWindowDestroy: + fprintf(stderr, "SelectionWindowDestroy.\n"); + break; + case SelectionClientClose: + fprintf(stderr, "SelectionClientClose.\n"); + break; + default: + fprintf(stderr, ".\n"); + break; + } + #endif + + info.selection = &CurrentSelections[i]; + info.kind = xfixesEvent->xfixesselection.subtype; + CallCallbacks(&SelectionCallback, &info); + } + } + return 1; +} + +int nxagentHandleProxyEvent(XEvent *X) +{ + switch (X -> xclient.data.l[0]) + { + case NXNoSplitNotify: + case NXStartSplitNotify: + { + /* + * We should never receive such events + * in the event loop, as they should + * be caught at the time the split is + * initiated. + */ + + #ifdef PANIC + + int client = (int) X -> xclient.data.l[1]; + + if (X -> xclient.data.l[0] == NXNoSplitNotify) + { + fprintf(stderr, "nxagentHandleProxyEvent: PANIC! NXNoSplitNotify received " + "with client [%d].\n", client); + } + else + { + fprintf(stderr, "nxagentHandleProxyEvent: PANIC! NXStartSplitNotify received " + "with client [%d].\n", client); + } + + #endif + + return 1; + } + case NXCommitSplitNotify: + { + /* + * We need to commit an image. Image can be the + * result of a PutSubImage() generated by Xlib, + * so there can be more than a single image to + * commit, even if only one PutImage was perfor- + * med by the agent. + */ + + int client = (int) X -> xclient.data.l[1]; + int request = (int) X -> xclient.data.l[2]; + int position = (int) X -> xclient.data.l[3]; + + #ifdef TEST + fprintf(stderr, "nxagentHandleProxyEvent: NXCommitSplitNotify received with " + "client [%d] request [%d] and position [%d].\n", + client, request, position); + #endif + + nxagentHandleCommitSplitEvent(client, request, position); + + return 1; + } + case NXEndSplitNotify: + { + /* + * All images for the split were transferred and + * we need to restart the client. + */ + + int client = (int) X -> xclient.data.l[1]; + + #ifdef TEST + fprintf(stderr, "nxagentHandleProxyEvent: NXEndSplitNotify received with " + "client [%d].\n", client); + #endif + + nxagentHandleEndSplitEvent(client); + + return 1; + } + case NXEmptySplitNotify: + { + /* + * All splits have been completed and none remain. + */ + + #ifdef TEST + fprintf(stderr, "nxagentHandleProxyEvent: NXEmptySplitNotify received.\n"); + #endif + + nxagentHandleEmptySplitEvent(); + + return 1; + } + case NXCollectPropertyNotify: + { + #ifdef TEST + int resource = (int) X -> xclient.data.l[1]; + + fprintf(stderr, "nxagentHandleProxyEvent: NXCollectPropertyNotify received with resource [%d].\n", + resource); + #endif + + nxagentHandleCollectPropertyEvent(X); + + return 1; + } + case NXCollectGrabPointerNotify: + { + int resource = (int) X -> xclient.data.l[1]; + + #ifdef TEST + fprintf(stderr, "nxagentHandleProxyEvent: NXCollectGrabPointerNotify received with resource [%d].\n", + resource); + #endif + + nxagentHandleCollectGrabPointerEvent(resource); + + return 1; + } + case NXCollectInputFocusNotify: + { + int resource = (int) X -> xclient.data.l[1]; + + /* + * This is not used at the present moment. + */ + + #ifdef TEST + fprintf(stderr, "nxagentHandleProxyEvent: NXCollectInputFocusNotify received with resource [%d].\n", + resource); + #endif + + nxagentHandleCollectInputFocusEvent(resource); + + return 1; + } + default: + { + /* + * Not a recognized ClientMessage event. + */ + + #ifdef WARNING + fprintf(stderr, "nxagentHandleProxyEvent: WARNING! Not a recognized ClientMessage proxy event [%d].\n", + (int) X -> xclient.data.l[0]); + #endif + + return 0; + } + } +} + +/* + * In this function it is assumed that we never + * get a configure with both stacking order and + * geometry changed, this way we can ignore + * stacking changes if the geometry has changed. + */ + +int nxagentCheckWindowConfiguration(XConfigureEvent* X) +{ + static int x = 0; + static int y = 0; + static int width = 0; + static int height = 0; + static Window win = None; + Bool geometryChanged = False; + + XlibWindow root_return = 0; + XlibWindow parent_return = 0; + XlibWindow *children_return = NULL; + unsigned int nchildren_return = 0; + Status result; + + if (win == X -> window) + { + if (x != X -> x || + y != X -> y || + width != X -> width || + height != X -> height) + { + geometryChanged = True; + } + } + + win = X -> window; + + x = X -> x; + y = X -> y; + width = X -> width; + height = X -> height; + + if (geometryChanged) + { + #ifdef TEST + fprintf(stderr, "nxagentCheckWindowConfiguration: Configure frame. No restack.\n"); + #endif + + return 1; + } + + #ifdef TEST + { + WindowPtr pSib; + + fprintf(stderr, "nxagentCheckWindowConfiguration: Before restacking top level window [%p]\n", + (void *) nxagentWindowPtr(X -> window)); + + for (pSib = screenInfo.screens[0]->root -> firstChild; pSib; pSib = pSib -> nextSib) + { + fprintf(stderr, "nxagentCheckWindowConfiguration: Top level window: [%p].\n", + (void *) pSib); + } + } + #endif + + result = XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + &root_return, &parent_return, &children_return, &nchildren_return); + + if (result) + { + nxagentRootlessRestack(children_return, nchildren_return); + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckWindowConfiguration: WARNING! Failed QueryTree request.\n"); + #endif + } + + if (result && nchildren_return) + { + XFree(children_return); + } + + #if 0 + fprintf(stderr, "nxagentCheckWindowConfiguration: Trees match: %s\n", + nxagentRootlessTreesMatch() ? "Yes" : "No"); + #endif + + return 1; +} + +int nxagentHandleConfigureNotify(XEvent* X) +{ + if (nxagentOption(Rootless) == True) + { + ClientPtr pClient; + WindowPtr pWinWindow; + WindowPtr pWin; + int sendEventAnyway = 0; + + pWinWindow = nxagentWindowPtr(X -> xconfigure.window); + + #ifdef TEST + { + WindowPtr pWinEvent = nxagentWindowPtr(X -> xconfigure.event); + + fprintf(stderr, "nxagentHandleConfigureNotify: Generating window is [%p][%ld] target [%p][%ld].\n", + (void *) pWinEvent, X -> xconfigure.event, (void *) pWinWindow, X -> xconfigure.window); + } + #endif + + #ifdef TEST + fprintf(stderr, "nxagentHandleConfigureNotify: New configuration for window [%p][%ld] is [%d][%d][%d][%d] " + "send_event [%i].\n", (void *) pWinWindow, X -> xconfigure.window, + X -> xconfigure.x, X -> xconfigure.y, X -> xconfigure.width, + X -> xconfigure.height, X -> xconfigure.send_event); + #endif + + if ((pWin = nxagentRootlessTopLevelWindow(X -> xconfigure.window)) != NULL) + { + /* + * Cheking for new geometry or stacking order changes. + */ + + nxagentCheckWindowConfiguration((XConfigureEvent*)X); + + return 1; + } + + if (nxagentWindowTopLevel(pWinWindow) && !X -> xconfigure.override_redirect) + { + XID values[5]; + Mask mask = 0; + + register XID *value = values; + + pClient = wClient(pWinWindow); + + if (X -> xconfigure.send_event || !nxagentWMIsRunning || + X -> xconfigure.override_redirect) + { + *value++ = (XID)X -> xconfigure.x; + *value++ = (XID)X -> xconfigure.y; + + /* + * nxagentWindowPriv(pWinWindow)->x = X -> xconfigure.x; + * nxagentWindowPriv(pWinWindow)->y = X -> xconfigure.y; + */ + + mask |= CWX | CWY; + } + + *value++ = (XID)X -> xconfigure.width; + *value++ = (XID)X -> xconfigure.height; + *value++ = (XID)X -> xconfigure.border_width; + + /* + * We don't need width and height here. + * + * nxagentWindowPriv(pWinWindow)->width = X -> xconfigure.width; + * nxagentWindowPriv(pWinWindow)->height = X -> xconfigure.height; + */ + + mask |= CWHeight | CWWidth | CWBorderWidth; + + nxagentScreenTrap = 1; + + ConfigureWindow(pWinWindow, mask, (XID *) values, pClient); + + nxagentScreenTrap = 0; + + nxagentCheckWindowConfiguration((XConfigureEvent*)X); + + /* + * This workaround should help with + * Java 1.6.0 that seems to ignore + * non-synthetic events. + */ + + if (nxagentOption(ClientOs) == ClientOsWinnt) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConfigureNotify: Apply workaround for NXWin.\n"); + #endif + + sendEventAnyway = 1; + } + + if (sendEventAnyway || X -> xconfigure.send_event) + { + xEvent x; + + memset(&x, 0, sizeof(xEvent)); + x.u.u.type = X -> xconfigure.type; + x.u.u.type |= 0x80; + + x.u.configureNotify.event = pWinWindow -> drawable.id; + x.u.configureNotify.window = pWinWindow -> drawable.id; + + if (pWinWindow -> nextSib) + { + x.u.configureNotify.aboveSibling = pWinWindow -> nextSib -> drawable.id; + } + else + { + x.u.configureNotify.aboveSibling = None; + } + + x.u.configureNotify.x = X -> xconfigure.x; + x.u.configureNotify.y = X -> xconfigure.y; + x.u.configureNotify.width = X -> xconfigure.width; + x.u.configureNotify.height = X -> xconfigure.height; + x.u.configureNotify.borderWidth = X -> xconfigure.border_width; + x.u.configureNotify.override = X -> xconfigure.override_redirect; + + TryClientEvents(pClient, &x, 1, 1, 1, 0); + } + + return 1; + } + } + else + { + /* + * Save the position of the agent default window. Don't + * save the values if the agent is in fullscreen mode. + * + * If we use these values to restore the position of a + * window after that we have dynamically changed the + * fullscreen attribute, depending on the behaviour of + * window manager, we could be not able to place the + * window exactly in the requested position, so let the + * window manager do the job for us. + */ + + ScreenPtr pScreen = nxagentScreen(X -> xconfigure.window); + + Bool doRandR = False; + struct timeval timeout; + + if (X -> xconfigure.window == nxagentDefaultWindows[pScreen -> myNum]) + { + if (nxagentOption(AllScreens) == 0) + { + if (nxagentOption(DesktopResize) == 1) + { + if (nxagentOption(Width) != X -> xconfigure.width || + nxagentOption(Height) != X -> xconfigure.height || + nxagentOption(X) != X -> xconfigure.x || + nxagentOption(Y) != X -> xconfigure.y) + { + Bool newEvents = False; + + doRandR = True; + + NXFlushDisplay(nxagentDisplay, NXFlushLink); + + do + { + newEvents = False; + + timeout.tv_sec = 0; + timeout.tv_usec = 500 * 1000; + + nxagentWaitEvents(nxagentDisplay, &timeout); + + /* + * This should also flush + * the NX link for us. + */ + + XSync(nxagentDisplay, 0); + + while (XCheckTypedWindowEvent(nxagentDisplay, nxagentDefaultWindows[pScreen -> myNum], + ConfigureNotify, X)) + { + newEvents = True; + } + + } while (newEvents); + } + } + + if (nxagentWMIsRunning == 0 || X -> xconfigure.send_event) + { + nxagentChangeOption(X, X -> xconfigure.x); + nxagentChangeOption(Y, X -> xconfigure.y); + } + + if (nxagentOption(Shadow) == 1 && nxagentOption(DesktopResize) == 1 && + (nxagentOption(Width) != X -> xconfigure.width || + nxagentOption(Height) != X -> xconfigure.height)) + { + nxagentShadowResize = 1; + } + + nxagentChangeOption(Width, X -> xconfigure.width); + nxagentChangeOption(Height, X -> xconfigure.height); + + nxagentChangeOption(ViewportXSpan, (int) X -> xconfigure.width - + (int) nxagentOption(RootWidth)); + nxagentChangeOption(ViewportYSpan, (int) X -> xconfigure.height - + (int) nxagentOption(RootHeight)); + + nxagentMoveViewport(pScreen, 0, 0); + + /* if in shadowing mode or if neither size nor position have + changed we do not need to adjust RandR */ + /* FIXME: Comment makes no sense */ + if (nxagentOption(Shadow) == 1 || + (nxagentOption(Width) == nxagentOption(RootWidth) && + nxagentOption(Height) == nxagentOption(RootHeight) && + nxagentOption(X) == nxagentOption(RootX) && + nxagentOption(Y) == nxagentOption(RootY))) + { + doRandR = False; + } + + nxagentChangeOption(Width, X -> xconfigure.width); + nxagentChangeOption(Height, X -> xconfigure.height); + + XMoveResizeWindow(nxagentDisplay, nxagentInputWindows[0], 0, 0, + X -> xconfigure.width, X -> xconfigure.height); + + if (nxagentOption(Fullscreen) == 0) + { + nxagentMoveViewport(pScreen, 0, 0); + } + else + { + nxagentChangeOption(RootX, (nxagentOption(Width) - + nxagentOption(RootWidth)) / 2); + nxagentChangeOption(RootY, (nxagentOption(Height) - + nxagentOption(RootHeight)) / 2); + nxagentChangeOption(ViewportXSpan, nxagentOption(Width) - + nxagentOption(RootWidth)); + nxagentChangeOption(ViewportYSpan, nxagentOption(Height) - + nxagentOption(RootHeight)); + + nxagentUpdateViewportFrame(0, 0, nxagentOption(RootWidth), + nxagentOption(RootHeight)); + + XMoveWindow(nxagentDisplay, nxagentWindow(pScreen->root), + nxagentOption(RootX), nxagentOption(RootY)); + } + + if (doRandR) + { + #ifdef TEST + fprintf(stderr,"nxagentHandleConfigureNotify: Width %d Height %d.\n", + nxagentOption(Width), nxagentOption(Height)); + #endif + + nxagentChangeScreenConfig(0, nxagentOption(Width), + nxagentOption(Height), 0, 0); + } + } + + return 1; + } + else + { + if ( (X -> xconfigure.window == DefaultRootWindow(nxagentDisplay)) || nxagentFullscreenWindow ) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConfigureNotify: remote root window has changed: %d,%d %dx%d\n", X -> xconfigure.x, X -> xconfigure.y, X -> xconfigure.width, X -> xconfigure.height); + #endif + + nxagentChangeOption(RootX, X -> xconfigure.x); + nxagentChangeOption(RootY, X -> xconfigure.y); + nxagentChangeOption(RootWidth, X -> xconfigure.width); + nxagentChangeOption(RootHeight, X -> xconfigure.height); + + nxagentChangeScreenConfig(0, nxagentOption(Width), + nxagentOption(Height), 0, 0); + + return 1; + } + } + } + + return 0; +} + +int nxagentHandleReparentNotify(XEvent* X) +{ + #ifdef TEST + fprintf(stderr, "nxagentHandleReparentNotify: Going to handle a new reparent event.\n"); + #endif + + if (nxagentOption(Rootless)) + { + WindowPtr pWin; + + XlibWindow w; + XlibWindow root_return = 0; + XlibWindow parent_return = 0; + XlibWindow *children_return = NULL; + unsigned int nchildren_return = 0; + Status result; + + pWin = nxagentWindowPtr(X -> xreparent.window); + + #ifdef TEST + + { + WindowPtr pParent = nxagentWindowPtr(X -> xreparent.parent); + WindowPtr pEvent = nxagentWindowPtr(X -> xreparent.event); + + fprintf(stderr, "nxagentHandleReparentNotify: event %p[%lx] window %p[%lx] parent %p[%lx] at (%d, %d)\n", + (void*)pEvent, X -> xreparent.event, (void*)pWin, X -> xreparent.window, + (void*)pParent, X -> xreparent.parent, X -> xreparent.x, X -> xreparent.y); + } + + #endif + + if (nxagentWindowTopLevel(pWin)) + { + /* + * If the window manager reparents our top level + * window, we need to know the new top level + * ancestor. + */ + + w = None; + parent_return = X -> xreparent.parent; + + while (parent_return != RootWindow(nxagentDisplay, 0)) + { + w = parent_return; + result = XQueryTree(nxagentDisplay, w, &root_return, + &parent_return, &children_return, &nchildren_return); + + if (!result) + { + #ifdef WARNING + fprintf(stderr, "nxagentHandleReparentNotify: WARNING! Failed QueryTree request.\n"); + #endif + + break; + } + + if (result && children_return) + { + XFree(children_return); + } + } + + if (w && !nxagentWindowPtr(w)) + { + XSelectInput(nxagentDisplay, w, StructureNotifyMask); + + nxagentRootlessAddTopLevelWindow(pWin, w); + + #ifdef TEST + fprintf(stderr, "nxagentHandleReparentNotify: new top level window [%ld].\n", w); + fprintf(stderr, "nxagentHandleReparentNotify: reparented window [%ld].\n", + X -> xreparent.window); + #endif + + result = XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + &root_return, &parent_return, &children_return, &nchildren_return); + + if (result) + { + nxagentRootlessRestack(children_return, nchildren_return); + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentHandleReparentNotify: WARNING! Failed QueryTree request.\n"); + #endif + } + + if (result && nchildren_return) + { + XFree(children_return); + } + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentHandleReparentNotify: Window at [%p] has been reparented to [%ld]" + " top level parent [%ld].\n", (void *) pWin, X -> xreparent.parent, w); + #endif + + nxagentRootlessDelTopLevelWindow(pWin); + } + } + + return 1; + } + else if (nxagentWMIsRunning == 1 && nxagentOption(Fullscreen) == 0 && + nxagentOption(WMBorderWidth) == -1) + { + XlibWindow w; + XlibWindow rootReturn = 0; + XlibWindow parentReturn = 0; + XlibWindow junk; + XlibWindow *childrenReturn = NULL; + unsigned int nchildrenReturn = 0; + Status result; + XWindowAttributes attributes; + int x, y; + int xParent, yParent; + + /* + * Calculate the absolute upper-left X e Y + */ + + if ((XGetWindowAttributes(nxagentDisplay, X -> xreparent.window, + &attributes) == 0)) + { + #ifdef WARNING + fprintf(stderr, "nxagentHandleReparentNotify: WARNING! " + "XGetWindowAttributes failed.\n"); + #endif + + return 1; + } + + x = attributes.x; + y = attributes.y; + + XTranslateCoordinates(nxagentDisplay, X -> xreparent.window, + attributes.root, -attributes.border_width, + -attributes.border_width, &x, &y, &junk); + + /* + * Calculate the parent X and parent Y. + */ + + w = X -> xreparent.parent; + + if (w != DefaultRootWindow(nxagentDisplay)) + { + do + { + result = XQueryTree(nxagentDisplay, w, &rootReturn, &parentReturn, + &childrenReturn, &nchildrenReturn); + + if (parentReturn == rootReturn || parentReturn == 0 || result == 0) + { + break; + } + + if (result == 1 && childrenReturn != NULL) + { + XFree(childrenReturn); + } + + w = parentReturn; + } + while (True); + + /* + * WM reparented. Find edge of the frame. + */ + + if (XGetWindowAttributes(nxagentDisplay, w, &attributes) == 0) + { + #ifdef WARNING + fprintf(stderr, "nxagentHandleReparentNotify: WARNING! " + "XGetWindowAttributes failed for parent window.\n"); + #endif + + return 1; + } + + xParent = attributes.x; + yParent = attributes.y; + + /* + * Difference between Absolute X and Parent X gives thickness of side frame. + * Difference between Absolute Y and Parent Y gives thickness of title bar. + */ + + nxagentChangeOption(WMBorderWidth, (x - xParent)); + nxagentChangeOption(WMTitleHeight, (y - yParent)); + } + } + + return 1; +} + +void nxagentEnableKeyboardEvents() +{ + int i; + Mask mask; + + nxagentGetDefaultEventMask(&mask); + + mask |= NXAGENT_KEYBOARD_EVENT_MASK; + + nxagentSetDefaultEventMask(mask); + + for (i = 0; i < nxagentNumScreens; i++) + { + XSelectInput(nxagentDisplay, nxagentDefaultWindows[i], mask); + } + + XkbSelectEvents(nxagentDisplay, XkbUseCoreKbd, + NXAGENT_KEYBOARD_EXTENSION_EVENT_MASK, + NXAGENT_KEYBOARD_EXTENSION_EVENT_MASK); +} + +void nxagentDisableKeyboardEvents() +{ + int i; + Mask mask; + + nxagentGetDefaultEventMask(&mask); + + mask &= ~NXAGENT_KEYBOARD_EVENT_MASK; + + nxagentSetDefaultEventMask(mask); + + for (i = 0; i < nxagentNumScreens; i++) + { + XSelectInput(nxagentDisplay, nxagentDefaultWindows[i], mask); + } + + XkbSelectEvents(nxagentDisplay, XkbUseCoreKbd, 0x0, 0x0); +} + +void nxagentEnablePointerEvents() +{ + int i; + Mask mask; + + nxagentGetDefaultEventMask(&mask); + + mask |= NXAGENT_POINTER_EVENT_MASK; + + nxagentSetDefaultEventMask(mask); + + for (i = 0; i < nxagentNumScreens; i++) + { + XSelectInput(nxagentDisplay, nxagentDefaultWindows[i], mask); + } +} + +void nxagentDisablePointerEvents() +{ + int i; + Mask mask; + + nxagentGetDefaultEventMask(&mask); + + mask &= ~NXAGENT_POINTER_EVENT_MASK; + + nxagentSetDefaultEventMask(mask); + + for (i = 0; i < nxagentNumScreens; i++) + { + XSelectInput(nxagentDisplay, nxagentDefaultWindows[i], mask); + } +} + +void nxagentSendFakeKey(int key) +{ + xEvent fake; + Time now; + + now = GetTimeInMillis(); + + memset(&fake, 0, sizeof(xEvent)); + fake.u.u.type = KeyPress; + fake.u.u.detail = key; + fake.u.keyButtonPointer.time = now; + + mieqEnqueue(&fake); + + fake.u.u.type = KeyRelease; + fake.u.u.detail = key; + fake.u.keyButtonPointer.time = now; + + mieqEnqueue(&fake); +} + +int nxagentInitKeyboardState() +{ + XEvent X; + + unsigned int modifiers; + + XkbEvent *xkbev = (XkbEvent *) &X; + + #ifdef TEST + fprintf(stderr, "nxagentInitKeyboardState: Initializing XKB state.\n"); + #endif + + memset(&X, 0, sizeof(XEvent)); + + XkbGetIndicatorState(nxagentDisplay, XkbUseCoreKbd, &modifiers); + + xkbev -> state.locked_mods = 0x0; + + if (modifiers & CAPSFLAG_IN_REPLY) + { + xkbev -> state.locked_mods |= CAPSFLAG_IN_EVENT; + } + + if (modifiers & NUMFLAG_IN_REPLY) + { + xkbev -> state.locked_mods |= NUMFLAG_IN_EVENT; + } + + #ifdef TEST + fprintf(stderr, "nxagentInitKeyboardState: Assuming XKB locked modifier bits [%x].\n", + xkbev -> state.locked_mods); + #endif + + xkbev -> type = nxagentXkbInfo.EventBase + XkbEventCode; + xkbev -> any.xkb_type = XkbStateNotify; + + nxagentHandleKeyboardEvent(&X); + + return 1; +} + +int nxagentWaitForResource(GetResourceFuncPtr pGetResource, PredicateFuncPtr pPredicate) +{ + int resource; + + while ((resource = (*pGetResource)(nxagentDisplay)) == -1) + { + if (nxagentWaitEvents(nxagentDisplay, NULL) == -1) + { + return -1; + } + + nxagentDispatchEvents(pPredicate); + } + + return resource; +} + +void nxagentGrabPointerAndKeyboard(XEvent *X) +{ + unsigned long now; + + int resource; + + int result; + + #ifdef TEST + fprintf(stderr, "nxagentGrabPointerAndKeyboard: Grabbing pointer and keyboard with event at [%p].\n", + (void *) X); + #endif + + if (X != NULL) + { + now = X -> xcrossing.time; + } + else + { + now = CurrentTime; + } + + #ifdef TEST + fprintf(stderr, "nxagentGrabPointerAndKeyboard: Going to grab the keyboard in context [B1].\n"); + #endif + + result = XGrabKeyboard(nxagentDisplay, nxagentFullscreenWindow, + True, GrabModeAsync, GrabModeAsync, now); + + if (result != GrabSuccess) + { + return; + } + + /* + * The smart scheduler could be stopped while + * waiting for the reply. In this case we need + * to yield explicitly to avoid to be stuck in + * the dispatch loop forever. + */ + + isItTimeToYield = 1; + + #ifdef TEST + fprintf(stderr, "nxagentGrabPointerAndKeyboard: Going to grab the pointer in context [B2].\n"); + #endif + + resource = nxagentWaitForResource(NXGetCollectGrabPointerResource, + nxagentCollectGrabPointerPredicate); + + NXCollectGrabPointer(nxagentDisplay, resource, + nxagentFullscreenWindow, True, NXAGENT_POINTER_EVENT_MASK, + GrabModeAsync, GrabModeAsync, None, None, now); + + /* + * This should not be needed. + * + * XGrabKey(nxagentDisplay, AnyKey, AnyModifier, nxagentFullscreenWindow, + * True, GrabModeAsync, GrabModeAsync); + */ + + if (X != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentGrabPointerAndKeyboard: Going to force focus in context [B4].\n"); + #endif + + XSetInputFocus(nxagentDisplay, nxagentFullscreenWindow, + RevertToParent, now); + } +} + +void nxagentUngrabPointerAndKeyboard(XEvent *X) +{ + unsigned long now; + + #ifdef TEST + fprintf(stderr, "nxagentUngrabPointerAndKeyboard: Ungrabbing pointer and keyboard with event at [%p].\n", + (void *) X); + #endif + + if (X != NULL) + { + now = X -> xcrossing.time; + } + else + { + now = CurrentTime; + } + + #ifdef TEST + fprintf(stderr, "nxagentUngrabPointerAndKeyboard: Going to ungrab the keyboard in context [B5].\n"); + #endif + + XUngrabKeyboard(nxagentDisplay, now); + + #ifdef TEST + fprintf(stderr, "nxagentGrabPointerAndKeyboard: Going to ungrab the pointer in context [B6].\n"); + #endif + + XUngrabPointer(nxagentDisplay, now); +} + +void nxagentDeactivatePointerGrab() +{ + GrabPtr grab = inputInfo.pointer -> grab; + + XButtonEvent X; + + if (grab) + { + X.type = ButtonRelease; + X.serial = 0; + X.send_event = FALSE; + X.time = currentTime.milliseconds; + X.display = nxagentDisplay; + X.window = nxagentWindow(grab -> window); + X.root = RootWindow(nxagentDisplay, 0); + X.subwindow = 0; + X.x = X.y = X.x_root = X.y_root = 0; + X.state = 0x100; + X.button = 1; + X.same_screen = TRUE; + + XPutBackEvent(nxagentDisplay, (XEvent*)&X); + } +} + +Bool nxagentCollectGrabPointerPredicate(Display *display, XEvent *X, XPointer ptr) +{ + return (X -> xclient.window == 0 && + X -> xclient.message_type == 0 && + X -> xclient.format == 32 && + X -> xclient.data.l[0] == NXCollectGrabPointerNotify); +} + +void nxagentHandleCollectGrabPointerEvent(int resource) +{ + int status; + + if (NXGetCollectedGrabPointer(nxagentDisplay, resource, &status) == 0) + { + #ifdef PANIC + fprintf(stderr, "nxagentHandleCollectGrabPointerEvent: PANIC! Failed to get GrabPointer " + "reply for resource [%d].\n", resource); + #endif + } +} + +void nxagentHandleCollectPropertyEvent(XEvent *X) +{ + Window window; + Atom property; + Atom atomReturnType; + int resultFormat; + unsigned long ulReturnItems; + unsigned long ulReturnBytesLeft; + unsigned char *pszReturnData = NULL; + int result; + int resource; + + resource = X -> xclient.data.l[1]; + + if (X -> xclient.data.l[2] == False) + { + #ifdef DEBUG + fprintf (stderr, "nxagentHandleCollectPropertyEvent: Failed to get reply data for client [%d].\n", + resource); + #endif + + return; + } + + if (resource == nxagentLastClipboardClient) + { + nxagentCollectPropertyEvent(resource); + } + else + { + result = NXGetCollectedProperty(nxagentDisplay, + resource, + &atomReturnType, + &resultFormat, + &ulReturnItems, + &ulReturnBytesLeft, + &pszReturnData); + + if (result == True) + { + window = nxagentPropertyRequests[resource].window; + property = nxagentPropertyRequests[resource].property; + + nxagentImportProperty(window, property, atomReturnType, resultFormat, + ulReturnItems, ulReturnBytesLeft, pszReturnData); + } + + if (result == 0) + { + #ifdef DEBUG + fprintf (stderr, "nxagentHandleCollectPropertyEvent: Failed to get reply data for client [%d].\n", + resource); + #endif + } + + if (pszReturnData != NULL) + { + XFree(pszReturnData); + } + + return; + } +} + +void nxagentSynchronizeExpose(void) +{ + WindowPtr pWin; + + if (nxagentExposeQueue.length <= 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeExpose: PANIC! Called with nxagentExposeQueue.length [%d].\n", + nxagentExposeQueue.length); + #endif + + return; + } + + pWin = nxagentExposeQueueHead.pWindow; + + if (pWin) + { + if ((nxagentExposeQueueHead.localRegion) != NullRegion) + { + RegionTranslate((nxagentExposeQueueHead.localRegion), + pWin -> drawable.x, pWin -> drawable.y); + } + + if ((nxagentExposeQueueHead.remoteRegion) != NullRegion) + { + RegionTranslate((nxagentExposeQueueHead.remoteRegion), + pWin -> drawable.x, pWin -> drawable.y); + } + + if ((nxagentExposeQueueHead.localRegion) != NullRegion && + (nxagentExposeQueueHead.remoteRegion) != NullRegion) + { + RegionSubtract((nxagentExposeQueueHead.remoteRegion), + (nxagentExposeQueueHead.remoteRegion), + (nxagentExposeQueueHead.localRegion)); + + if (RegionNil(nxagentExposeQueueHead.remoteRegion) == 0 && + ((pWin -> eventMask|wOtherEventMasks(pWin)) & ExposureMask)) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeExpose: Going to call miWindowExposures" + " for window [%ld] - rects [%ld].\n", nxagentWindow(pWin), + RegionNumRects(nxagentExposeQueueHead.remoteRegion)); + #endif + + miWindowExposures(pWin, nxagentExposeQueueHead.remoteRegion, NullRegion); + } + } + } + + nxagentExposeQueueHead.pWindow = NULL; + + if (nxagentExposeQueueHead.localRegion != NullRegion) + { + RegionDestroy(nxagentExposeQueueHead.localRegion); + } + + nxagentExposeQueueHead.localRegion = NullRegion; + + if (nxagentExposeQueueHead.remoteRegion != NullRegion) + { + RegionDestroy(nxagentExposeQueueHead.remoteRegion); + } + + nxagentExposeQueueHead.remoteRegion = NullRegion; + + nxagentExposeQueueHead.remoteRegionIsCompleted = False; + + nxagentExposeQueue.start = (nxagentExposeQueue.start + 1) % EXPOSED_SIZE; + + nxagentExposeQueue.length--; + + return; +} + +int nxagentLookupByWindow(WindowPtr pWin) +{ + int i; + int j; + + for (j = 0; j < nxagentExposeQueue.length; j++) + { + i = (nxagentExposeQueue.start + j) % EXPOSED_SIZE; + + if (nxagentExposeQueue.exposures[i].pWindow == pWin && + !nxagentExposeQueue.exposures[i].remoteRegionIsCompleted) + { + return i; + } + } + + return -1; +} + +void nxagentRemoveDuplicatedKeys(XEvent *X) +{ + _XQEvent *prev; + _XQEvent *qelt; + + _XQEvent *qeltKeyRelease; + _XQEvent *prevKeyRelease; + + KeyCode lastKeycode = X -> xkey.keycode; + + qelt = nxagentDisplay -> head; + + if (qelt == NULL) + { + #ifdef TEST + + int more; + + fprintf(stderr, "nxagentRemoveDuplicatedKeys: Trying to read more events " + "from the X server.\n"); + + more = nxagentReadEvents(nxagentDisplay); + + if (more > 0) + { + fprintf(stderr, "nxagentRemoveDuplicatedKeys: Successfully read more events " + "from the X server.\n"); + } + + #else + + nxagentReadEvents(nxagentDisplay); + + #endif + + qelt = nxagentDisplay -> head; + } + + if (qelt != NULL) + { + prev = qeltKeyRelease = prevKeyRelease = NULL; + + LockDisplay(nxagentDisplay); + + while (qelt != NULL) + { + if (qelt -> event.type == KeyRelease || + qelt -> event.type == KeyPress) + { + if (qelt -> event.xkey.keycode != lastKeycode || + (qelt -> event.type == KeyPress && qeltKeyRelease == NULL) || + (qelt -> event.type == KeyRelease && qeltKeyRelease != NULL)) + { + break; + } + + if (qelt -> event.type == KeyRelease) + { + prevKeyRelease = prev; + + qeltKeyRelease = qelt; + } + else if (qelt -> event.type == KeyPress) + { + _XDeq(nxagentDisplay, prev, qelt); + + qelt = prev -> next; + + if (prev == qeltKeyRelease) + { + prev = prevKeyRelease; + } + + _XDeq(nxagentDisplay, prevKeyRelease, qeltKeyRelease); + + qeltKeyRelease = prevKeyRelease = NULL; + + continue; + } + } + + prev = qelt; + + qelt = qelt -> next; + } + + UnlockDisplay(nxagentDisplay); + } +} + +void nxagentInitRemoteExposeRegion(void) +{ + if (nxagentRemoteExposeRegion == NULL) + { + nxagentRemoteExposeRegion = RegionCreate(NULL, 1); + + if (nxagentRemoteExposeRegion == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentInitRemoteExposeRegion: PANIC! Failed to create expose region.\n"); + #endif + } + } +} + +void nxagentForwardRemoteExpose(void) +{ + if (RegionNotEmpty(nxagentRemoteExposeRegion)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentForwardRemoteExpose: Going to forward events.\n"); + #endif + + TraverseTree(screenInfo.screens[0]->root, nxagentClipAndSendExpose, (void *)nxagentRemoteExposeRegion); + + /* + * Now this region should be empty. + */ + + RegionEmpty(nxagentRemoteExposeRegion); + } +} + +void nxagentAddRectToRemoteExposeRegion(BoxPtr rect) +{ + RegionRec exposeRegion; + + if (nxagentRemoteExposeRegion == NULL) + { + return; + } + + RegionInit(&exposeRegion, rect, 1); + + RegionUnion(nxagentRemoteExposeRegion, + nxagentRemoteExposeRegion, &exposeRegion); + + RegionUninit(&exposeRegion); +} + +int nxagentClipAndSendExpose(WindowPtr pWin, void * ptr) +{ + RegionPtr exposeRgn; + RegionPtr remoteExposeRgn; + + #ifdef DEBUG + BoxRec box; + + fprintf(stderr, "nxagentClipAndSendExpose: Called.\n"); + #endif + + remoteExposeRgn = (RegionRec *) ptr; + + if (pWin -> drawable.class != InputOnly) + { + exposeRgn = RegionCreate(NULL, 1); + + #ifdef DEBUG + box = *RegionExtents(remoteExposeRgn); + + fprintf(stderr, "nxagentClipAndSendExpose: Root expose extents: [%d] [%d] [%d] [%d].\n", + box.x1, box.y1, box.x2, box.y2); + + box = *RegionExtents(&pWin -> clipList); + + fprintf(stderr, "nxagentClipAndSendExpose: Clip list extents for window at [%p]: [%d] [%d] [%d] [%d].\n", + pWin, box.x1, box.y1, box.x2, box.y2); + #endif + + RegionIntersect(exposeRgn, remoteExposeRgn, &pWin -> clipList); + + if (RegionNotEmpty(exposeRgn)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentClipAndSendExpose: Forwarding expose to window at [%p] pWin.\n", + pWin); + #endif + + /* + * The miWindowExposures() clears out the + * region parameters, so the subtract ope- + * ration must be done before calling it. + */ + + RegionSubtract(remoteExposeRgn, remoteExposeRgn, exposeRgn); + + miWindowExposures(pWin, exposeRgn, NullRegion); + } + + RegionDestroy(exposeRgn); + } + + if (RegionNotEmpty(remoteExposeRgn)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentClipAndSendExpose: Region not empty. Walk children.\n"); + #endif + + return WT_WALKCHILDREN; + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentClipAndSendExpose: Region empty. Stop walking.\n"); + #endif + + return WT_STOPWALKING; + } +} + +int nxagentUserInput(void *p) +{ + int result = 0; + + /* + * This function is used as callback in + * the polling handler of agent in shadow + * mode. When inside the polling loop the + * handlers are never called, so we have + * to dispatch enqueued events to eventu- + * ally change the nxagentInputEvent sta- + * tus. + */ + + if (nxagentOption(Shadow) == 1 && + nxagentPendingEvents(nxagentDisplay) > 0) + { + nxagentDispatchEvents(NULL); + } + + if (nxagentInputEvent == 1) + { + nxagentInputEvent = 0; + + result = 1; + } + + /* + * The agent working in shadow mode synch- + * ronizes the remote X server even if a + * button/key is not released (i.e. when + * scrolling a long browser's page), in + * order to update the screen smoothly. + */ + + if (nxagentOption(Shadow) == 1) + { + return result; + } + + if (result == 0) + { + /* + * If there is at least one button/key down, + * we are receiving an input. This is not a + * condition to break a synchronization loop + * if there is enough bandwidth. + */ + + if (nxagentCongestion > 0 && + (inputInfo.pointer -> button -> buttonsDown > 0 || + nxagentKeyDown > 0)) + { + #ifdef TEST + fprintf(stderr, "nxagentUserInput: Buttons [%d] Keys [%d].\n", + inputInfo.pointer -> button -> buttonsDown, nxagentKeyDown); + #endif + + result = 1; + } + } + + return result; +} + +int nxagentHandleRRScreenChangeNotify(XEvent *X) +{ + XRRScreenChangeNotifyEvent *Xr; + + #ifdef DEBUG + fprintf(stderr, "nxagentHandleRRScreenChangeNotify called.\n"); + #endif + + Xr = (XRRScreenChangeNotifyEvent *) X; + + nxagentResizeScreen(screenInfo.screens[DefaultScreen(nxagentDisplay)], Xr -> width, Xr -> height, + Xr -> mwidth, Xr -> mheight); + + nxagentShadowCreateMainWindow(screenInfo.screens[DefaultScreen(nxagentDisplay)], screenInfo.screens[0]->root, + Xr -> width, Xr -> height); + + nxagentShadowSetWindowsSize(); + + return 1; +} + +/* + * Returns true if there is any event waiting to + * be dispatched. This function is critical for + * the performance because it is called very, + * very often. It must also handle the case when + * the display is down. The display descriptor, + * in fact, may have been reused by some other + * client. + */ + +int nxagentPendingEvents(Display *dpy) +{ + if (_XGetIOError(dpy) != 0) + { + #ifdef DEBUG + fprintf(stderr, "nxagentPendingEvents: Returning error with display down.\n"); + #endif + + return -1; + } + else if (XQLength(dpy) > 0) + { + #ifdef DEBUG + fprintf(stderr, "nxagentPendingEvents: Returning true with [%d] events queued.\n", + XQLength(dpy)); + #endif + + return 1; + } + else + { + int result; + int readable; + + result = NXTransReadable(dpy -> fd, &readable); + + if (result == 0) + { + if (readable > 0) + { + #ifdef DEBUG + fprintf(stderr, "nxagentPendingEvents: Returning true with [%d] bytes readable.\n", + readable); + #endif + + return 1; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentPendingEvents: Returning false with [%d] bytes readable.\n", + readable); + #endif + + return 0; + } + + #ifdef TEST + fprintf(stderr, "nxagentPendingEvents: WARNING! Error detected on the X display.\n"); + #endif + + NXForceDisplayError(dpy); + + return -1; + } +} + +/* + * Blocks until an event becomes + * available. + */ + +int nxagentWaitEvents(Display *dpy, struct timeval *tm) +{ + XEvent ev; + + #ifdef DEBUG + fprintf(stderr, "nxagentWaitEvents called.\n"); + #endif + + NXFlushDisplay(dpy, NXFlushLink); + + /* + * If the transport is not running we + * have to rely on Xlib to wait for an + * event. In this case the timeout is + * ignored. + */ + + if (NXTransRunning(NX_FD_ANY) == 1) + { + NXTransContinue(tm); + } + else + { + XPeekEvent(dpy, &ev); + } + + /* + * Check if we encountered a display + * error. If we did, wait for the + * time requested by the caller. + */ + + if (NXDisplayError(dpy) == 1) + { + if (tm != NULL) + { + usleep(tm -> tv_sec * 1000 * 1000 + + tm -> tv_usec); + } + + return -1; + } + + return 1; +} + +#ifdef NX_DEBUG_INPUT + +void nxagentDumpInputInfo(void) +{ + fprintf(stderr, "Dumping input info ON.\n"); +} + +void nxagentGuessDumpInputInfo(ClientPtr client, Atom property, char *data) +{ + if (strcmp(validateString(NameForAtom(property)), "NX_DEBUG_INPUT") == 0) + { + if (*data != 0) + { + nxagentDebugInput = 1; + } + else + { + nxagentDebugInput = 0; + } + } +} + +void nxagentDeactivateInputDevicesGrabs() +{ + fprintf(stderr, "Info: Deactivating input devices grabs.\n"); + + if (inputInfo.pointer -> grab) + { + (*inputInfo.pointer -> DeactivateGrab)(inputInfo.pointer); + } + + if (inputInfo.keyboard -> grab) + { + (*inputInfo.keyboard -> DeactivateGrab)(inputInfo.keyboard); + } +} + +static const char *nxagentGrabStateToString(int state) +{ + switch (state) + { + case 0: + return "NOT_GRABBED"; + case 1: + return "THAWED"; + case 2: + return "THAWED_BOTH"; + case 3: + return "FREEZE_NEXT_EVENT"; + case 4: + return "FREEZE_BOTH_NEXT_EVENT"; + case 5: + return "FROZEN_NO_EVENT"; + case 6: + return "FROZEN_WITH_EVENT"; + case 7: + return "THAW_OTHERS"; + default: + return "unknown state"; + } +} + +void nxagentDumpInputDevicesState(void) +{ + int i, k; + int mask = 1; + CARD8 val; + DeviceIntPtr dev; + GrabPtr grab; + WindowPtr pWin = NULL; + + fprintf(stderr, "\n*** Dump input devices state: BEGIN ***" + "\nKeys down:"); + + dev = inputInfo.keyboard; + + for (i = 0; i < DOWN_LENGTH; i++) + { + val = dev -> key -> down[i]; + + if (val != 0) + { + for (k = 0; k < 8; k++) + { + if (val & (mask << k)) + { + fprintf(stderr, "\n\t[%d] [%s]", i * 8 + k, + XKeysymToString(XKeycodeToKeysym(nxagentDisplay, i * 8 + k, 0))); + } + } + } + } + + fprintf(stderr, "\nKeyboard device state: \n\tdevice [%p]\n\tlast grab time [%lu]" + "\n\tfrozen [%s]\n\tstate [%s]\n\tother [%p]\n\tevent count [%d]" + "\n\tfrom passive grab [%s]\n\tactivating key [%d]", dev, + dev -> grabTime.milliseconds, dev -> sync.frozen ? "Yes": "No", + nxagentGrabStateToString(dev -> sync.state), + dev -> sync.other, dev -> sync.evcount, + dev -> fromPassiveGrab ? "Yes" : "No", + dev -> activatingKey); + + grab = dev -> grab; + + if (grab) + { + fprintf(stderr, "\nKeyboard grab state: \n\twindow pointer [%p]" + "\n\towner events flag [%s]\n\tgrab mode [%s]", + grab -> window, grab -> ownerEvents ? "True" : "False", + grab -> keyboardMode ? "asynchronous" : "synchronous"); + + /* + * Passive grabs. + */ + + pWin = grab -> window; + grab = wPassiveGrabs(pWin); + + while (grab) + { + fprintf(stderr, "\nPassive grab state: \n\tdevice [%p]\n\towner events flag [%s]" + "\n\tpointer grab mode [%s]\n\tkeyboard grab mode [%s]\n\tevent type [%d]" + "\n\tmodifiers [%x]\n\tbutton/key [%u]\n\tevent mask [%lx]", + grab -> device, grab -> ownerEvents ? "True" : "False", + grab -> pointerMode ? "asynchronous" : "synchronous", + grab -> keyboardMode ? "asynchronous" : "synchronous", + grab -> type, grab -> modifiersDetail.exact, + grab -> detail.exact, grab -> eventMask); + + grab = grab -> next; + } + } + + fprintf(stderr, "\nButtons down:"); + + dev = inputInfo.pointer; + + for (i = 0; i < DOWN_LENGTH; i++) + { + val = dev -> button -> down[i]; + + if (val != 0) + { + for (k = 0; k < 8; k++) + { + if (val & (mask << k)) + { + fprintf(stderr, "\n\t[%d]", i * 8 + k); + } + } + } + } + + fprintf(stderr, "\nPointer device state: \n\tdevice [%p]\n\tlast grab time [%lu]" + "\n\tfrozen [%s]\n\tstate [%s]\n\tother [%p]\n\tevent count [%d]" + "\n\tfrom passive grab [%s]\n\tactivating button [%d]", dev, + dev -> grabTime.milliseconds, dev -> sync.frozen ? "Yes" : "No", + nxagentGrabStateToString(dev -> sync.state), + dev -> sync.other, dev -> sync.evcount, + dev -> fromPassiveGrab ? "Yes" : "No", + dev -> activatingKey); + + grab = dev -> grab; + + if (grab) + { + fprintf(stderr, "\nPointer grab state: \n\twindow pointer [%p]" + "\n\towner events flag [%s]\n\tgrab mode [%s]", + grab -> window, grab -> ownerEvents ? "True" : "False", + grab -> pointerMode ? "asynchronous" : "synchronous"); + + if (grab -> window != pWin) + { + /* + * Passive grabs. + */ + + grab = wPassiveGrabs(grab -> window); + + while (grab) + { + fprintf(stderr, "\nPassive grab state: \n\tdevice [%p]\n\towner events flag [%s]" + "\n\tpointer grab mode [%s]\n\tkeyboard grab mode [%s]\n\tevent type [%d]" + "\n\tmodifiers [%x]\n\tbutton/key [%u]\n\tevent mask [%lx]", + grab -> device, grab -> ownerEvents ? "True" : "False", + grab -> pointerMode ? "asynchronous" : "synchronous", + grab -> keyboardMode ? "asynchronous" : "synchronous", + grab -> type, grab -> modifiersDetail.exact, + grab -> detail.exact, grab -> eventMask); + + grab = grab -> next; + } + } + } + + fprintf(stderr, "\n*** Dump input devices state: FINISH ***\n"); +} + +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/Events.h b/nx-X11/programs/Xserver/hw/nxagent/Events.h new file mode 100644 index 000000000..7d313c331 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Events.h @@ -0,0 +1,238 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Events_H__ +#define __Events_H__ + +#include <nx-X11/Xmd.h> + +#define ProcessedExpose (LASTEvent + 1) +#define ProcessedNotify (LASTEvent + 2) + +#define EXPOSED_SIZE 256 + +enum HandleEventResult +{ + doNothing = 0, + doMinimize, + doDebugTree, + doCloseSession, + doStartKbd, + doSwitchFullscreen, + doSwitchAllScreens, + doViewportMoveUp, + doViewportMoveLeft, + doViewportMoveRight, + doViewportMoveDown, + doViewportLeft, + doViewportUp, + doViewportRight, + doViewportDown, + doSwitchResizeMode, + doSwitchDeferMode +}; + +extern CARD32 nxagentLastEventTime; + +/* + * Manage incoming events. + */ + +typedef Bool (*PredicateFuncPtr)(Display*, XEvent*, XPointer); + +extern void nxagentDispatchEvents(PredicateFuncPtr); + +typedef int (*GetResourceFuncPtr)(Display*); + +int nxagentWaitForResource(GetResourceFuncPtr, PredicateFuncPtr); + +Bool nxagentCollectGrabPointerPredicate(Display *display, XEvent *X, XPointer ptr); + +int nxagentInputEventPredicate(Display *display, XEvent *event, XPointer parameter); + +/* + * Enable and disable notification of + * remote X server events. + */ + +extern void nxagentEnableKeyboardEvents(void); +extern void nxagentEnablePointerEvents(void); + +extern void nxagentDisableKeyboardEvents(void); +extern void nxagentDisablePointerEvents(void); + +/* + * Manage default event mask. + */ + +extern void nxagentInitDefaultEventMask(void); +extern void nxagentGetDefaultEventMask(Mask *mask_return); +extern void nxagentSetDefaultEventMask(Mask mask); +extern void nxagentGetEventMask(WindowPtr pWin, Mask *mask_return); + +/* + * Bring keyboard device in known state. It needs + * a round-trip so it only gets called if a pre- + * vious XKB event did not implicitly initialized + * the internal state. This is unlikely to happen. + */ + +extern int nxagentInitKeyboardState(void); + +/* + * Update the keyboard state according + * to focus and XKB events received + * from the remote X server. + */ + +extern int nxagentHandleKeyboardEvent(XEvent *X); + +/* + * Handle sync and karma messages and + * other notification event coming + * from proxy. + */ + +extern int nxagentHandleProxyEvent(XEvent *X); + +/* + * Other functions providing the ad-hoc + * handling of the remote X events. + */ + +extern int nxagentHandleExposeEvent(XEvent *X); +extern int nxagentHandleGraphicsExposeEvent(XEvent *X); +extern int nxagentHandleClientMessageEvent(XEvent *X, enum HandleEventResult*); +extern int nxagentHandlePropertyNotify(XEvent *X); +extern int nxagentHandleKeyPress(XEvent *X, enum HandleEventResult*); +extern int nxagentHandleReparentNotify(XEvent *X); +extern int nxagentHandleConfigureNotify(XEvent *X); +extern int nxagentHandleXFixesSelectionNotify(XEvent *X); + +/* + * Send a fake keystroke to the remote + * X server. + */ + +extern void nxagentSendFakeKey(int key); + +/* + * Called to manage grab of pointer and + * keyboard when running in fullscreen + * mode. + */ + +extern void nxagentGrabPointerAndKeyboard(XEvent *X); +extern void nxagentUngrabPointerAndKeyboard(XEvent *X); + +extern void nxagentDeactivatePointerGrab(void); + +/* + * Handle the selection property received + * in the event loop. + */ + +void nxagentCollectPropertyEvent(int resource); + +/* + * Synchronize expose events between agent and + * the real X server. + */ + +typedef struct _ExposuresRec +{ + WindowPtr pWindow; + RegionPtr localRegion; + RegionPtr remoteRegion; + Bool remoteRegionIsCompleted; + int serial; + int synchronize; + +} ExposuresRec; + +extern RegionPtr nxagentRemoteExposeRegion; + +typedef struct _ExposeQueue +{ + unsigned int start; + int length; + ExposuresRec exposures[EXPOSED_SIZE]; +} ExposeQueue; + +extern void nxagentSynchronizeExpose(void); +extern int nxagentLookupByWindow(WindowPtr pWin); +extern void nxagentUpdateExposeArray(void); + +extern ExposeQueue nxagentExposeQueue; + +/* + * Handle the split related notifications. + */ + +int nxagentWaitSplitEvent(int resource); + +void nxagentHandleNoSplitEvent(int resource); +void nxagentHandleStartSplitEvent(int resource); +void nxagentHandleCommitSplitEvent(int resource, int request, int position); +void nxagentHandleEndSplitEvent(int resource); +void nxagentHandleEmptySplitEvent(void); + +void nxagentInitRemoteExposeRegion(void); +void nxagentAddRectToRemoteExposeRegion(BoxPtr); + +extern int nxagentUserInput(void *p); + +/* +* We have to check these before launching the terminate + * dialog in rootless mode. + */ + +extern Bool nxagentLastWindowDestroyed; +extern Time nxagentLastWindowDestroyedTime; + +/* + * Set this flag if an user input event is received. + */ + +extern int nxagentInputEvent; + +/* + * Event-handling utilities. + */ + +Bool nxagentPendingEvents(Display *dpy); + +#define nxagentQueuedEvents(display) \ + XQLength((display)) + +#define nxagentReadEvents(display) \ + XEventsQueued((display), QueuedAfterReading) + +#define nxagentCheckEvents(display, event, predicate, argument) \ + XCheckIfEventNoFlush((display), (event), (predicate), (argument)) + +int nxagentWaitEvents(Display *, struct timeval *); + +#endif /* __Events_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Extensions.c b/nx-X11/programs/Xserver/hw/nxagent/Extensions.c new file mode 100644 index 000000000..d9db1a8aa --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Extensions.c @@ -0,0 +1,470 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "micmap.h" +#include "scrnintstr.h" +#include "../../randr/randrstr.h" + +#include "Agent.h" +#include "Display.h" +#include "Screen.h" +#include "Options.h" +#include "Extensions.h" +#include "Windows.h" + +void GlxExtensionInit(void); +void GlxWrapInitVisuals(void *procPtr); + +static int nxagentRandRScreenSetSize(ScreenPtr pScreen, CARD16 width, + CARD16 height, CARD32 mmWidth, + CARD32 mmHeight); + +static int nxagentRandRInitSizes(ScreenPtr pScreen); + +#if RANDR_14_INTERFACE +static Bool +nxagentRandRReplaceScanoutPixmap(DrawablePtr pDrawable, + PixmapPtr pPixmap, + Bool enable); +#endif + +#if RANDR_13_INTERFACE +static Bool +nxagentRandROutputGetProperty(ScreenPtr pScreen, + RROutputPtr output, + Atom property); +static Bool +nxagentRandRGetPanning(ScreenPtr pScrn, + RRCrtcPtr crtc, + BoxPtr totalArea, + BoxPtr trackingArea, + INT16 *border); +static Bool +nxagentRandRSetPanning(ScreenPtr pScrn, + RRCrtcPtr crtc, + BoxPtr totalArea, + BoxPtr trackingArea, + INT16 *border); +#endif + +#if RANDR_12_INTERFACE +static Bool nxagentRandRCrtcSet (ScreenPtr pScreen, RRCrtcPtr crtc, + RRModePtr mode, int x, int y, + Rotation rotation, int numOutputs, + RROutputPtr *outputs); +#endif + +#ifdef __DARWIN__ + +void DarwinHandleGUI(int argc, char *argv[]) +{ +} + +void DarwinGlxExtensionInit() +{ + GlxExtensionInit(); +} + +void DarwinGlxWrapInitVisuals(void *procPtr) +{ + GlxWrapInitVisuals(procPtr); +} + +#endif + +void nxagentInitGlxExtension(VisualPtr *visuals, DepthPtr *depths, + int *numVisuals, int *numDepths, int *rootDepth, + VisualID *defaultVisual) +{ + miInitVisualsProcPtr initVisuals; + + /* + * Initialize the visuals to use the GLX extension. + */ + + initVisuals = NULL; + + GlxWrapInitVisuals(&initVisuals); + + if (initVisuals(visuals, depths, numVisuals, numDepths, + rootDepth, defaultVisual, 0, 0, 0) == 0) + { + fprintf(stderr, "Warning: Failed to initialize the GLX extension.\n"); + } +} + +void nxagentInitRandRExtension(ScreenPtr pScreen) +{ + rrScrPrivPtr pRandRScrPriv; + + if (RRScreenInit(pScreen) == 0) + { + fprintf(stderr, "Warning: Failed to initialize the RandR extension.\n"); + } + + + /* FIXME: do we need this at all with the new rand/xinerama stuff? */ + nxagentRandRInitSizes(pScreen); + + /* + * RRScreenInit sets these pointers to NULL, + * so requiring the server to set up its own + * replacements. + */ + + pRandRScrPriv = rrGetScrPriv(pScreen); + + pRandRScrPriv -> rrGetInfo = nxagentRandRGetInfo; + + #if RANDR_15_INTERFACE + /* nothing to be assigned here, so far */ + #endif + + #if RANDR_14_INTERFACE + /* no pixmap sharing in nx-X11 */ + pScreen->ReplaceScanoutPixmap = nxagentRandRReplaceScanoutPixmap; + pRandRScrPriv -> rrCrtcSetScanoutPixmap = NULL; + + /* only fake provider support in nx-X11, so far */ + pRandRScrPriv -> provider = RRProviderCreate(pScreen, "default", 7); + pRandRScrPriv -> rrProviderSetOutputSource = NULL; + pRandRScrPriv -> rrProviderSetOffloadSink = NULL; + pRandRScrPriv -> rrProviderGetProperty = NULL; + pRandRScrPriv -> rrProviderSetProperty = NULL; + #endif + + #if RANDR_13_INTERFACE + pRandRScrPriv -> rrOutputGetProperty = nxagentRandROutputGetProperty; + pRandRScrPriv -> rrGetPanning = nxagentRandRGetPanning; + pRandRScrPriv -> rrSetPanning = nxagentRandRSetPanning; + #endif + + #if RANDR_12_INTERFACE + pRandRScrPriv -> rrScreenSetSize = nxagentRandRScreenSetSize; + pRandRScrPriv -> rrCrtcSet = nxagentRandRCrtcSet; + #endif + + #if RANDR_10_INTERFACE + pRandRScrPriv -> rrSetConfig = nxagentRandRSetConfig; + #endif +} + +#if RANDR_14_INTERFACE +static Bool +nxagentRandRReplaceScanoutPixmap(DrawablePtr pDrawable, + PixmapPtr pPixmap, + Bool enable) +{ + /* FALSE means: not supported */ +#ifdef DEBUG + fprintf(stderr, "nxagentRandRReplaceScanoutPixmap: NX's RANDR does not support scan-out pixmaps.\n"); +#endif + return FALSE; +} +#endif + +#if RANDR_13_INTERFACE +static Bool +nxagentRandROutputGetProperty(ScreenPtr pScreen, + RROutputPtr output, + Atom property) +{ + /* FALSE means: no property required to be modified on the fly here */ + return FALSE; +} + +static Bool +nxagentRandRGetPanning(ScreenPtr pScrn, + RRCrtcPtr crtc, + BoxPtr totalArea, + BoxPtr trackingArea, + INT16 *border) +{ + /* FALSE means: no, panning is not supported at the moment... + * Panning requires several modes to be available for + * the NX<n> output(s). + * + * FIXME: Add more modes per output than the current window size. + * At least when in fullscreen mode. + */ +#ifdef DEBUG + fprintf(stderr, "nxagentRandRGetPanning: RANDR Panning is currently not supported.\n"); +#endif + return FALSE; +} + +static Bool +nxagentRandRSetPanning(ScreenPtr pScrn, + RRCrtcPtr crtc, + BoxPtr totalArea, + BoxPtr trackingArea, + INT16 *border) +{ + /* FALSE means: no, panning is not supported at the moment... + * Panning requires several modes to be available for + * the NX<n> output(s). + * + * FIXME: Add more modes per output than the current window size. + * At least when in fullscreen mode. + */ +#ifdef DEBUG + fprintf(stderr, "nxagentRandRSetPanning: RANDR Panning is currently not supported.\n"); +#endif + return FALSE; +} +#endif + +#if RANDR_12_INTERFACE +/* + * Request that the Crtc be reconfigured + */ + +static Bool +nxagentRandRCrtcSet (ScreenPtr pScreen, + RRCrtcPtr crtc, + RRModePtr mode, + int x, + int y, + Rotation rotation, + int numOutputs, + RROutputPtr *outputs) +{ + return RRCrtcNotify(crtc, mode, x, y, rotation, NULL, numOutputs, outputs); +} +#endif + + +int nxagentRandRGetInfo(ScreenPtr pScreen, Rotation *pRotations) +{ + /* + * Rotation is not supported. + */ + + *pRotations = RR_Rotate_0; + + return 1; +} + +static int nxagentRandRInitSizes(ScreenPtr pScreen) +{ + RRScreenSizePtr pSize; + + int width; + int height; + + int maxWidth; + int maxHeight; + +/* + int w[] = {0, 160, 320, 640, 800, 1024, 1152, 1280, 1280, 1280, 1280, 1280, + 1280, 1360, 1440, 1600, 1600, 1680, 1920, 1920, 0, 0}; + int h[] = {0, 120, 240, 480, 600, 768, 864, 600, 720, 800, 854, 960, + 1024, 768, 900, 900, 1200, 1050, 1080, 1200, 0, 0}; +*/ + int w[] = {0, 320, 640, 640, 800, 800, 1024, 1024, 1152, 1280, 1280, 1280, 1360, + 1440, 1600, 1600, 1680, 1920, 1920, 0, 0}; + int h[] = {0, 240, 360, 480, 480, 600, 600, 768, 864, 720, 800, 1024, 768, + 900, 900, 1200, 1050, 1080, 1200, 0, 0}; + + int i; + int nSizes; + + int mmWidth; + int mmHeight; + + /* + * Register all the supported sizes. The third + * parameter is the refresh rate. + */ + + maxWidth = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + maxHeight = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + + nSizes = sizeof w / sizeof(int); + + /* + * Add current and max sizes. + */ + + w[nSizes - 1] = pScreen -> width; + h[nSizes - 1] = pScreen -> height; + + w[nSizes - 2] = maxWidth; + h[nSizes - 2] = maxHeight; + + /* + * Compute default size. + */ + + w[0] = w[2]; + h[0] = h[2]; + + for (i = 3; i < nSizes - 1; i++) + { + if ((w[i] <= maxWidth * 3 / 4) && + (h[i] <= maxHeight * 3 / 4) && + (w[i] >= w[0]) && + (h[i] >= h[0])) + { + w[0] = w[i]; + h[0] = h[i]; + } + } + + for (i = 0; i < nSizes; i++) + { + width = w[i]; + height = h[i]; + + mmWidth = (width * 254 + monitorResolution * 5) / (monitorResolution * 10); + + if (mmWidth < 1) + { + mmWidth = 1; + } + + mmHeight = (height * 254 + monitorResolution * 5) / (monitorResolution * 10); + + if (mmHeight < 1) + { + mmHeight = 1; + } + + pSize = RRRegisterSize(pScreen, width, height, mmWidth, mmHeight); + + if (pSize == NULL) + { + return 0; + } + + RRRegisterRate (pScreen, pSize, 60); + } + + RRSetCurrentConfig(pScreen, RR_Rotate_0, 60, pSize); + + return 1; +} + +#if RANDR_10_INTERFACE + +int nxagentRandRSetConfig(ScreenPtr pScreen, Rotation rotation, + int rate, RRScreenSizePtr pSize) +{ + int r; + + UpdateCurrentTime(); + + /* + * Whatever size is OK for us. + */ + + r = nxagentResizeScreen(pScreen, pSize -> width, pSize -> height, + pSize -> mmWidth, pSize -> mmHeight); + + nxagentMoveViewport(pScreen, 0, 0); + + return r; +} + +#endif + +#if RANDR_12_INTERFACE + +void nxagentRandRSetWindowsSize(int width, int height) +{ + if (width == 0) + { + if (nxagentOption(Fullscreen) == 1) + { + width = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + } + else + { + width = nxagentOption(Width); + } + } + + if (height == 0) + { + if (nxagentOption(Fullscreen) == 1) + { + height = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + } + else + { + height = nxagentOption(Height); + } + } + + XResizeWindow(nxagentDisplay, nxagentDefaultWindows[0], width, height); + + if (nxagentOption(Rootless) == 0) + { + XMoveResizeWindow(nxagentDisplay, nxagentInputWindows[0], 0, 0, width, + height); + } +} + +int nxagentRandRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height, + CARD32 mmWidth, CARD32 mmHeight) +{ + int result; + + UpdateCurrentTime(); + + if (nxagentOption(DesktopResize) == 1 && + (nxagentOption(Fullscreen) == 1 || + width > WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) || + height > HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)))) + { + if (nxagentOption(ClientOs) != ClientOsWinnt + /*&& nxagentOption(ClientOs) != ClientNXPlayer*/) + { + nxagentChangeOption(DesktopResize, 0); + } + } + + if (nxagentOption(DesktopResize) == 1 && nxagentOption(Fullscreen) == 0 && + nxagentOption(AllScreens) == 0) + { + nxagentChangeOption(Width, width); + nxagentChangeOption(Height, height); + } + + result = nxagentResizeScreen(pScreen, width, height, mmWidth, mmHeight); + + if (result == 1 && nxagentOption(DesktopResize) == 1 && + nxagentOption(Fullscreen) == 0 && nxagentOption(AllScreens) == 0) + { + nxagentRandRSetWindowsSize(width, height); + nxagentSetWMNormalHints(pScreen -> myNum); + } + + nxagentMoveViewport(pScreen, 0, 0); + + return result; +} + +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/Extensions.h b/nx-X11/programs/Xserver/hw/nxagent/Extensions.h new file mode 100644 index 000000000..9b3672f5a --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Extensions.h @@ -0,0 +1,43 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * Initialize the additional extensions. + */ + +void nxagentInitGlxExtension(VisualPtr *visuals, DepthPtr *depths, + int *numVisuals, int *numDepths, int *rootDepth, + VisualID *defaultVisual); + +void nxagentInitRandRExtension(ScreenPtr pScreen); + +/* + * Basic interface to the RandR extension. + */ + +int nxagentRandRGetInfo(ScreenPtr pScreen, Rotation *pRotations); + +int nxagentRandRSetConfig(ScreenPtr pScreen, Rotation rotation, + int rate, RRScreenSizePtr pSize); diff --git a/nx-X11/programs/Xserver/hw/nxagent/Font.c b/nx-X11/programs/Xserver/hw/nxagent/Font.c new file mode 100644 index 000000000..f9c682765 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Font.c @@ -0,0 +1,1864 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include "scrnintstr.h" +#include "dixstruct.h" +#include <X11/fonts/font.h> +#include <X11/fonts/fontstruct.h> +#include "dixfontstr.h" +#include "misc.h" +#include "miscstruct.h" +#include "opaque.h" + +#include "Agent.h" + +#include "Display.h" +#include "Font.h" +#include "Error.h" + +#include <stdio.h> +#include <sys/stat.h> +#include "resource.h" +#include "Reconnect.h" + +#include "Args.h" +#include "Utils.h" + +#include "compext/Compext.h" +#include <nx/NXalert.h> + +#include <string.h> +#include <stdlib.h> + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define NXAGENT_DEFAULT_FONT_DIR "/usr/share/nx/fonts" +#define NXAGENT_ALTERNATE_FONT_DIR "/usr/share/X11/fonts" +#define NXAGENT_ALTERNATE_FONT_DIR_2 "/usr/share/fonts/X11" +#define NXAGENT_ALTERNATE_FONT_DIR_3 "/usr/X11R6/lib/X11/fonts" + +#define NXAGENT_DEFAULT_FONT_PATH \ +"/usr/share/nx/fonts/misc/,/usr/share/nx/fonts/Speedo/,\ +/usr/share/nx/fonts/Type1/,/usr/share/nx/fonts/75dpi/,\ +/usr/share/nx/fonts/100dpi/,/usr/share/nx/fonts/TTF/" + +#define NXAGENT_ALTERNATE_FONT_PATH \ +"/usr/share/X11/fonts/misc/,/usr/share/X11/fonts/Speedo/,\ +/usr/share/X11/fonts/Type1/,/usr/share/X11/fonts/75dpi/,\ +/usr/share/X11/fonts/100dpi/,/usr/share/X11/fonts/TTF/" + +#define NXAGENT_ALTERNATE_FONT_PATH_2 \ +"/usr/share/fonts/X11/misc/,/usr/share/fonts/X11/Speedo/,\ +/usr/share/fonts/X11/Type1/,/usr/share/fonts/X11/75dpi/,\ +/usr/share/fonts/X11/100dpi/,/usr/share/fonts/X11/TTF/" + +#define NXAGENT_ALTERNATE_FONT_PATH_3 \ +"/usr/X11R6/lib/X11/fonts/misc/,/usr/X11R6/lib/X11/fonts/Speedo/,\ +/usr/X11R6/lib/X11/fonts/Type1/,/usr/X11R6/lib/X11/fonts/75dpi/,\ +/usr/X11R6/lib/X11/fonts/100dpi/,/usr/X11R6/lib/X11/fonts/TTF/" + +#undef NXAGENT_FONTCACHE_DEBUG +#undef NXAGENT_RECONNECT_FONT_DEBUG +#undef NXAGENT_FONTMATCH_DEBUG + +#define FIELDS 14 + +static int reconnectFlexibility; + +static void nxagentCleanCacheAfterReconnect(void); +static void nxagentFontReconnect(FontPtr, XID, void *); +static XFontStruct *nxagentLoadBestQueryFont(Display* dpy, char *fontName, FontPtr pFont); +static XFontStruct *nxagentLoadQueryFont(register Display *dpy , char *fontName , FontPtr pFont); +int nxagentFreeFont(XFontStruct *fs); +static Bool nxagentGetFontServerPath(char * fontServerPath); + +static char * nxagentMakeScalableFontName(const char *fontName, int scalableResolution); + +RESTYPE RT_NX_FONT; + +#ifdef NXAGENT_RECONNECT_FONT_DEBUG +static void printFontCacheDump(char*); +#endif + +typedef struct _nxagentFontRec +{ + char *name; + int status; +} nxagentFontRec, *nxagentFontRecPtr; + +typedef struct _nxagentFontList +{ + nxagentFontRecPtr *list; + int length; + int listSize; +} nxagentFontList, *nxagentFontListPtr; + +nxagentFontList nxagentRemoteFontList = {NULL, (int)0, (int)0}; + +int nxagentFontPrivateIndex; + +typedef struct _nxCacheFontEntry +{ + Atom atom; + XFontStruct *font_struct; + char *name; +} nxCacheFontEntryRec, *nxCacheFontEntryRecPtr; + +static struct _nxagentFontCache +{ + nxCacheFontEntryRecPtr *entry; + int index; + int size; +} nxagentFontCache = { NULL, (int) 0, (int) 0 }; + +#define CACHE_ENTRY_PTR (nxagentFontCache.entry) +#define CACHE_INDEX (nxagentFontCache.index) +#define CACHE_SIZE (nxagentFontCache.size) +#define CACHE_ENTRY(A) (CACHE_ENTRY_PTR[A]) +#define CACHE_FSTRUCT(A) (CACHE_ENTRY(A) -> font_struct) +#define CACHE_NAME(A) (CACHE_ENTRY(A) -> name) +#define CACHE_ATOM(A) (CACHE_ENTRY(A) -> atom) + +static struct _nxagentFailedToReconnectFonts +{ + FontPtr *font; + XID *id; + int size; + int index; +} nxagentFailedToReconnectFonts = {NULL, NULL, 0, 0}; + +/* + * This is used if nxagentFullGeneration is true + * in CloseDisplay(). + */ + +void nxagentFreeFontCache(void) +{ + int i; + + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "Font: Freeing nxagent font cache\n"); + #endif + + if (CACHE_INDEX == 0) + return; + + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "Font: Freeing nxagent font cache, there are [%d] entries.\n", CACHE_INDEX); + #endif + + for (i = 0; i < CACHE_INDEX; i++) + { + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "Font: Freeing nxagent font cache entry [%d] entry pointer is [%p], name [%s]\n", + i, CACHE_ENTRY(i), CACHE_NAME(i)); + #endif + + if (CACHE_FSTRUCT(i)) + { + nxagentFreeFont(CACHE_FSTRUCT(i)); + } + + free(CACHE_NAME(i)); + free(CACHE_ENTRY(i)); + } + + free(CACHE_ENTRY_PTR); + CACHE_ENTRY_PTR = NULL; + CACHE_INDEX = 0; + CACHE_SIZE = 0; + + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "Font: nxagent font cache fully freed\n"); + #endif + + return; +} + +void nxagentListRemoteFonts(const char *searchPattern, const int maxNames) +{ + int i, q, p; + + char **xList; + int xLen = 0; + + const char *patterns[] = {"*", "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"}; + int patternsQt = 2; + + if (NXDisplayError(nxagentDisplay) == 1) + { + return; + } + + /* + * Avoid querying again the remote + * fonts. + */ + + if (nxagentRemoteFontList.length > 0) + { + return; + } + + /* + * We can't retrieve the full remote font + * list with a single query, because the + * number of dashes in the pattern acts as + * a rule to select how to search for the + * font names, so the pattern '*' is useful + * to retrive the font aliases, while the + * other one will select the 'real' fonts. + */ + + for (p = 0; p < patternsQt; p++) + { + xList = XListFonts(nxagentDisplay, patterns[p], maxNames, &xLen); + + #ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "nxagentListRemoteFonts: NXagent remote list [%s] has %d elements.\n", patterns[p], xLen); + #endif + + /* + * Add the ListFont request pattern to the list with + * the last requested maxnames. + */ + + nxagentListRemoteAddName(searchPattern, maxNames); + + for (i = 0; i < xLen; i++) + { + q = 1; + + nxagentListRemoteAddName(xList[i], q); + } + + XFreeFontNames(xList); + } + + #ifdef NXAGENT_FONTMATCH_DEBUG + + fprintf(stderr, "nxagentListRemoteFonts: Printing remote font list.\n"); + + for (i = 0; i < nxagentRemoteFontList.length; i++) + { + fprintf(stderr, "Font# %d, \"%s\"\n", i, nxagentRemoteFontList.list[i]->name); + } + + fprintf(stderr, "nxagentListRemoteFonts: End of list\n"); + + #endif +} + +void nxagentListRemoteAddName(const char *name, int status) +{ + int pos; + + if (nxagentFontFind(name, &pos)) + { + if (nxagentRemoteFontList.list[pos]->status < status) + { + nxagentRemoteFontList.list[pos]->status = status; + + #ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "Font: Font# %d, [%s] change status to %s\n", + pos, nxagentRemoteFontList.list[pos]->name,nxagentRemoteFontList.list[pos]->status?"OK":"deleted"); + #endif + } + return; + } + + if (nxagentRemoteFontList.length == nxagentRemoteFontList.listSize) + { + nxagentRemoteFontList.list = realloc(nxagentRemoteFontList.list, sizeof(nxagentFontRecPtr) + * (nxagentRemoteFontList.listSize + 1000)); + + if (nxagentRemoteFontList.list == NULL) + { + FatalError("Font: remote list memory re-allocation failed!.\n"); + } + + nxagentRemoteFontList.listSize += 1000; + } + + if (pos < nxagentRemoteFontList.length) + { + #ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "Font: Going to move list from %p to %p len = %d!.\n", + &nxagentRemoteFontList.list[pos], &nxagentRemoteFontList.list[pos+1], + (nxagentRemoteFontList.length - pos) * sizeof(nxagentFontRecPtr)); + #endif + + memmove(&nxagentRemoteFontList.list[pos+1], + &nxagentRemoteFontList.list[pos], + (nxagentRemoteFontList.length - pos) * sizeof(nxagentFontRecPtr)); + } + + if ((nxagentRemoteFontList.list[pos] = malloc(sizeof(nxagentFontRec)))) + { + nxagentRemoteFontList.list[pos]->name = malloc(strlen(name) +1); + if (nxagentRemoteFontList.list[pos]->name == NULL) + { + fprintf(stderr, "Font: remote list name memory allocation failed!.\n"); + return; + } + } + else + { + fprintf(stderr, "Font: remote list record memory allocation failed!.\n"); + return; + } + strcpy(nxagentRemoteFontList.list[pos]->name,name); + nxagentRemoteFontList.list[pos]->status = status; + nxagentRemoteFontList.length++; + + #ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "Font: remote font list added [%s] in position [%d] as %s !.\n", + name, pos, status ? "OK" : "deleted"); + fprintf(stderr, "Font: remote font list total len is [%d] Size is [%d] !.\n", + nxagentRemoteFontList.length, nxagentRemoteFontList.listSize); + #endif +} + +static void nxagentFreeRemoteFontList(nxagentFontList *listRec) +{ + int l; + + for (l = 0; l < listRec -> length; l++) + { + if (listRec -> list[l]) + { + free(listRec -> list[l] -> name); + listRec -> list[l] -> name = NULL; + + free(listRec -> list[l]); + listRec -> list[l] = NULL; + } + } + + listRec -> length = listRec -> listSize = 0; + + free(listRec -> list); + listRec -> list = NULL; + + return; +} + +Bool nxagentFontFind(const char *name, int *pos) +{ + int low,high,res,iter,lpos; + + if (!nxagentRemoteFontList.length) + { + *pos=0; + return False; + } + low = 0; + high = nxagentRemoteFontList.length - 1; + iter = 0; + res = 1; + lpos = nxagentRemoteFontList.length; + while (low <= high) + { + *pos = (high + low)/2; + iter ++; + res = strcasecmp(nxagentRemoteFontList.list[*pos]->name,name); + if (res > 0) + { + high = *pos - 1; + lpos = *pos; + continue; + } + else if (res < 0) + { + low = *pos + 1; + lpos = low; + continue; + } + break; + } + *pos = (res == 0)?*pos:lpos; + + #ifdef NXAGENT_FONTMATCH_DEBUG + if (res == 0) + fprintf(stderr, "Font: font found in %d iterations in pos = %d\n", iter, *pos); + else + fprintf(stderr, "Font: not font found in %d iterations insertion pos is = %d\n", iter, *pos); + #endif + + return (res == 0); + +} + +Bool nxagentFontLookUp(const char *name) +{ + int i; + int result; + + char *scalable; + + if (name != NULL && strlen(name) == 0) + { + return 0; + } + + result = nxagentFontFind(name, &i); + + scalable = NULL; + + /* + * Let's try with the scalable font description. + */ + + if (result == 0) + { + scalable = nxagentMakeScalableFontName(name, 0); + + if (scalable != NULL) + { + result = nxagentFontFind(scalable, &i); + + free(scalable); + } + } + + /* + * Let's try again after replacing zero to xdpi and ydpi in the pattern. + */ + + if (result == 0) + { + scalable = nxagentMakeScalableFontName(name, 1); + + if (scalable != NULL) + { + result = nxagentFontFind(scalable, &i); + + free(scalable); + } + } + + if (result == 0) + { + return 0; + } + else + { + return (nxagentRemoteFontList.list[i]->status > 0); + } +} + +Bool nxagentRealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + void * priv; + Atom name_atom, value_atom; + int nprops; + FontPropPtr props; + int i; + const char *name; + char *origName = (char*) pScreen; + +#ifdef HAS_XFONT2 + xfont2_font_set_private(pFont, nxagentFontPrivateIndex, NULL); +#else + FontSetPrivate(pFont, nxagentFontPrivateIndex, NULL); +#endif /* HAS_XFONT2 */ + + if (requestingClient && XpClientIsPrintClient(requestingClient, NULL)) + return True; + + name_atom = MakeAtom("FONT", 4, True); + value_atom = 0L; + + nprops = pFont->info.nprops; + props = pFont->info.props; + + for (i = 0; i < nprops; i++) + if ((Atom)props[i].name == name_atom) { + value_atom = props[i].value; + break; + } + + if (!value_atom) return False; + + name = NameForAtom(value_atom); + + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "Font: nxagentRealizeFont, realizing font: %s\n", validateString(name)); + fprintf(stderr, " atom: %ld\n", value_atom); + fprintf(stderr, "Font: Cache dump:\n"); + for (i = 0; i < CACHE_INDEX; i++) + { + fprintf(stderr, "nxagentFontCache.entry[%d]->name: %s font_struct at %p\n", + i, CACHE_NAME(i), CACHE_FSTRUCT(i)); + } + #endif + + if (!name) return False; + + if ((strcasecmp(origName, name) != 0) && !strchr(origName,'*')) + { + #ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "Font: Changing font name to realize from [%s] to [%s]\n", + validateString(name), origName); + #endif + + name = origName; + } + + priv = (void *)malloc(sizeof(nxagentPrivFont)); +#ifdef HAS_XFONT2 + xfont2_font_set_private(pFont, nxagentFontPrivateIndex, priv); +#else + FontSetPrivate(pFont, nxagentFontPrivateIndex, priv); +#endif /* HAS_XFONT2 */ + + nxagentFontPriv(pFont) -> mirrorID = 0; + + for (i = 0; i < nxagentFontCache.index; i++) + { +/* if (value_atom == CACHE_ATOM(i))*/ + if (strcasecmp(CACHE_NAME(i), name) == 0) + { + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "Font: nxagentFontCache hit [%s] = [%s]!\n", CACHE_NAME(i), validateString(name)); + #endif + + break; + } + } + + if (i < CACHE_INDEX) + { + nxagentFontPriv(pFont)->font_struct = CACHE_FSTRUCT(i); + strcpy(nxagentFontPriv(pFont)->fontName, name); + } + else + { + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "Font: nxagentFontCache fail.\n"); + #endif + + if (CACHE_INDEX == CACHE_SIZE) + { + CACHE_ENTRY_PTR = realloc(CACHE_ENTRY_PTR, sizeof(nxCacheFontEntryRecPtr) * (CACHE_SIZE + 100)); + + if (CACHE_ENTRY_PTR == NULL) + { + FatalError("Font: Cache list memory re-allocation failed.\n"); + } + + CACHE_SIZE += 100; + } + + CACHE_ENTRY(CACHE_INDEX) = malloc(sizeof(nxCacheFontEntryRec)); + + if (CACHE_ENTRY(CACHE_INDEX) == NULL) + { + return False; + } + + CACHE_NAME(CACHE_INDEX) = malloc(strlen(name) + 1); + + if (CACHE_NAME(CACHE_INDEX) == NULL) + { + return False; + } + + #ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "Font: Going to realize font [%s],[%s] on real X server.\n", validateString(name), origName); + #endif + + if (nxagentRemoteFontList.length == 0 && (NXDisplayError(nxagentDisplay) == 0)) + { + nxagentListRemoteFonts("*", nxagentMaxFontNames); + } + + nxagentFontPriv(pFont)->font_struct = nxagentLoadQueryFont(nxagentDisplay, (char *)name, pFont); + strcpy(nxagentFontPriv(pFont)->fontName, name); + if (nxagentFontPriv(pFont)->font_struct != NULL) + { + CACHE_ATOM(i) = value_atom; + strcpy(CACHE_NAME(i), name); + CACHE_FSTRUCT(i) = nxagentFontPriv(pFont)->font_struct; + CACHE_INDEX++; + + nxagentFontPriv(pFont) -> mirrorID = FakeClientID(serverClient -> index); + AddResource(nxagentFontPriv(pFont) -> mirrorID, RT_NX_FONT, pFont); + + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "Font: nxagentFontCache adds font [%s] in pos. [%d].\n", + validateString(name), CACHE_INDEX - 1); + #endif + } + } + + #ifdef NXAGENT_FONTMATCH_DEBUG + + if (nxagentFontPriv(pFont)->font_struct == NULL) + { + if (nxagentFontLookUp(name) == False) + { + fprintf(stderr, "Font: nxagentRealizeFont failed with font Font=%s, not in our remote list\n", + validateString(name)); + } + else + { + fprintf(stderr, "Font: nxagentRealizeFont failed with font Font=%s but the font is in our remote list\n", + validateString(name)); + } + } + else + fprintf(stderr, "Font: nxagentRealizeFont OK realizing font Font=%s\n", + validateString(name)); + + #endif + + return (nxagentFontPriv(pFont)->font_struct != NULL); +} + +Bool nxagentUnrealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + if (nxagentFontPriv(pFont)) + { + if (NXDisplayError(nxagentDisplay) == 0) + { + if (nxagentFontStruct(pFont)) + { + int i; + + for (i = 0; i < CACHE_INDEX; i++) + { + if (CACHE_FSTRUCT(i) == nxagentFontStruct(pFont)) + { + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "nxagentUnrealizeFont: Not freeing the font in cache.\n"); + #endif + + break; + } + } + + if (i == CACHE_INDEX) + { + /* + * This font is not in the cache. + */ + + #ifdef NXAGENT_FONTCACHE_DEBUG + fprintf(stderr, "nxagentUnrealizeFont: Freeing font not found in cache '%d'\n", + CACHE_ATOM(i)); + #endif + + XFreeFont(nxagentDisplay, nxagentFontStruct(pFont)); + } + } + } + + if (nxagentFontPriv(pFont) -> mirrorID) + FreeResource(nxagentFontPriv(pFont) -> mirrorID, RT_NONE); + + free(nxagentFontPriv(pFont)); +#ifdef HAS_XFONT2 + xfont2_font_set_private(pFont, nxagentFontPrivateIndex, NULL); +#else + FontSetPrivate(pFont, nxagentFontPrivateIndex, NULL); +#endif /* HAS_XFONT2 */ + } + + return True; +} + +int nxagentDestroyNewFontResourceType(void * p, XID id) +{ + #ifdef TEST + fprintf(stderr, "nxagentDestroyNewFontResourceType: Destroying mirror id [%ld] for font at [%p].\n", + nxagentFontPriv((FontPtr) p) -> mirrorID, (void *) p); + #endif + +/* +FIXME: It happens that this resource had been already + destroied. We should verify if the same font is + assigned both to the server client and another + client. We had a crash when freeing server client + resources. +*/ + if (nxagentFontPriv((FontPtr) p) != NULL) + { + nxagentFontPriv((FontPtr) p) -> mirrorID = None; + } + + return 1; +} + +static XFontStruct *nxagentLoadBestQueryFont(Display* dpy, char *fontName, FontPtr pFont) +{ + XFontStruct *fontStruct; + + char *substFontBuf; + + /* X Logical Font Description Conventions + * require 14 fields in the font names. + * + */ + char *searchFields[FIELDS+1]; + char *fontNameFields[FIELDS+1]; + int i; + int j; + int numSearchFields = 0; + int numFontFields = 0; + int weight = 0; + int tempWeight = 1; + int fieldOrder[14] = { 4, /* Slant */ + 11, /* Spacing */ + 12, /* Width info */ + 13, /* Charset */ + 14, /* Language */ + 7, /* Height */ + 6, /* Add-style */ + 3, /* Weight */ + 2, /* Name */ + 1, /* Foundry */ + 9, /* DPI_x */ + 5, /* Set-width */ + 8, /* Point size */ + 10 /* DPI_y */ + }; + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentLoadBestQueryFont: Searching font '%s' .\n", fontName); + #endif + + substFontBuf = (char *) malloc(sizeof(char) * 512); + + + numFontFields = nxagentSplitString(fontName, fontNameFields, FIELDS + 1, "-"); + + memcpy(substFontBuf, "fixed\0", strlen("fixed") + 1); + + if (numFontFields <= FIELDS) + { + #ifdef WARNING + if (nxagentVerbose == 1) + { + fprintf(stderr, "nxagentLoadBestQueryFont: WARNING! Font name in non standard format. \n"); + } + #endif + } + else + { + for (i = 1 ; i < nxagentRemoteFontList.length ; i++) + { + numSearchFields = nxagentSplitString(nxagentRemoteFontList.list[i]->name, searchFields, FIELDS+1, "-"); + + + /* The following code attemps to find an accurate approximation + * of the missing font. The current candidate and the missing font are + * compared on the 14 fields of the X Logical Font Description Convention. + * The selection is performed by the analysis of the matching fields, + * shifting left the value of the Weight variable on the right matches + * and shifting right the value of the Weight on the wrong ones; + * due a probability of overmuch right shifting, the starting weight is set + * to a high value. At the end of matching the selected font is the one + * with the bigger final Weight. The shift operation has been used instead + * of other operation for a performance issue. + * In some check the shift is performed by more than one position, because + * of the relevance of the field; for example a correct slant or a matching + * charset is more relevant than the size. + */ + + if (numSearchFields > FIELDS) + { + + tempWeight = 0; + + for (j = 0; j < FIELDS; j++) + { + if (strcasecmp(searchFields[fieldOrder[j]], fontNameFields[fieldOrder[j]]) == 0 || + strcmp(searchFields[fieldOrder[j]], "") == 0 || + strcmp(fontNameFields[fieldOrder[j]], "") != 0 || + strcmp(searchFields[fieldOrder[j]], "*") == 0 || + strcmp(fontNameFields[fieldOrder[j]], "*") == 0) + { + tempWeight ++; + } + + tempWeight <<= 1; + } + + } + + if (tempWeight > weight) + { + /* Found more accurate font */ + + weight = tempWeight; + memcpy(substFontBuf, nxagentRemoteFontList.list[i]->name, strlen(nxagentRemoteFontList.list[i]->name)); + substFontBuf[strlen(nxagentRemoteFontList.list[i]->name)] = '\0'; + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentLoadBestQueryFont: Weight '%d' of more accurate font '%s' .\n", weight, substFontBuf); + #endif + } + + for (j = 0; j < numSearchFields; j++) + { + if (searchFields[j] != NULL) + { + free(searchFields[j]); + } + } + } + } + + #ifdef WARNING + if (nxagentVerbose == 1) + { + fprintf(stderr, "nxagentLoadBestQueryFont: WARNING! Failed to load font '%s'. Replacing with '%s'.\n", + fontName, substFontBuf); + } + #endif + + fontStruct = nxagentLoadQueryFont(dpy, substFontBuf, pFont); + + free (substFontBuf); + + for (j = 0; j < numFontFields; j++) + { + if (fontNameFields[j] != NULL) + { + free(fontNameFields[j]); + } + } + + return fontStruct; +} + +static void nxagentFontDisconnect(FontPtr pFont, XID param1, void * param2) +{ + nxagentPrivFont *privFont; + Bool *pBool = (Bool*)param2; + int i; + + if (pFont == NULL || !*pBool) + return; + + privFont = nxagentFontPriv(pFont); + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentFontDisconnect: pFont %p, XID %lx\n", + (void *) pFont, privFont -> font_struct ? nxagentFont(pFont) : 0); + #endif + + for (i = 0; i < CACHE_INDEX; i++) + { + if (strcasecmp(CACHE_NAME(i), privFont -> fontName) == 0) + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentFontDisconnect: font %s found in cache at position %d\n", + privFont -> fontName, i); + #endif + + privFont -> font_struct = NULL; + return; + } + } + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentFontDisconnect: WARNING font %s not found in cache freeing it now\n", + privFont -> fontName); + #endif + + if (privFont -> font_struct) + { + XFreeFont(nxagentDisplay, privFont -> font_struct); + privFont -> font_struct = NULL; + } +} + +static void nxagentCollectFailedFont(FontPtr fpt, XID id) +{ + + if (nxagentFailedToReconnectFonts.font == NULL) + { + nxagentFailedToReconnectFonts.size = 8; + + nxagentFailedToReconnectFonts.font = malloc(nxagentFailedToReconnectFonts.size * + sizeof(FontPtr)); + + nxagentFailedToReconnectFonts.id = malloc(nxagentFailedToReconnectFonts.size * sizeof(XID)); + + if (nxagentFailedToReconnectFonts.font == NULL || nxagentFailedToReconnectFonts.id == NULL) + { + FatalError("Font: font not reconnected memory allocation failed!.\n"); + } + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentCollectFailedFont: allocated [%d] bytes.\n", + 8 * (sizeof(FontPtr)+ sizeof(XID))); + #endif + } + else if (nxagentFailedToReconnectFonts.index == nxagentFailedToReconnectFonts.size - 1) + { + nxagentFailedToReconnectFonts.size *= 2; + + nxagentFailedToReconnectFonts.font = realloc(nxagentFailedToReconnectFonts.font, + nxagentFailedToReconnectFonts.size * + sizeof(FontPtr)); + + nxagentFailedToReconnectFonts.id = realloc(nxagentFailedToReconnectFonts.id, + nxagentFailedToReconnectFonts.size * + sizeof(XID)); + + if (nxagentFailedToReconnectFonts.font == NULL || nxagentFailedToReconnectFonts.id == NULL) + { + FatalError("Font: font not reconnected memory re-allocation failed!.\n"); + } + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr,"nxagentCollectFailedFont: reallocated memory.\n "); + #endif + } + + nxagentFailedToReconnectFonts.font[nxagentFailedToReconnectFonts.index] = fpt; + + nxagentFailedToReconnectFonts.id[nxagentFailedToReconnectFonts.index] = id; + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentCollectFailedFont: font not reconnected at [%p], " + "put in nxagentFailedToReconnectFonts.font[%d] = [%p], with XID = [%lu].\n", + (void*) fpt, nxagentFailedToReconnectFonts.index, + (void *)nxagentFailedToReconnectFonts.font[nxagentFailedToReconnectFonts.index], + nxagentFailedToReconnectFonts.id[nxagentFailedToReconnectFonts.index]); + #endif + + nxagentFailedToReconnectFonts.index++; +} + +static void nxagentFontReconnect(FontPtr pFont, XID param1, void * param2) +{ + int i; + nxagentPrivFont *privFont; + Bool *pBool = (Bool*)param2; + + if (pFont == NULL) + return; + + privFont = nxagentFontPriv(pFont); + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentFontReconnect: pFont %p - XID %lx - name %s\n", + (void*) pFont, (privFont -> font_struct) ? nxagentFont(pFont) : 0, + privFont -> fontName); + #endif + + for (i = 0; i < CACHE_INDEX; i++) + { + if (strcasecmp(CACHE_NAME(i), privFont -> fontName) == 0) + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "\tfound in cache"); + #endif + + if (!CACHE_FSTRUCT(i)) + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, " --- font struct not valid\n"); + #endif + + break; + } + + nxagentFontStruct(pFont) = CACHE_FSTRUCT(i); + + return; + } + } + + if (i == CACHE_INDEX) + { + FatalError("nxagentFontReconnect: font not found in cache."); + } + + privFont -> font_struct = nxagentLoadQueryFont(nxagentDisplay, privFont -> fontName, pFont); + + if ((privFont -> font_struct == NULL) && reconnectFlexibility) + { + privFont -> font_struct = nxagentLoadBestQueryFont(nxagentDisplay, privFont -> fontName, pFont); + } + + if (privFont->font_struct != NULL) + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "\tXID %lx\n", privFont -> font_struct -> fid); + #endif + + CACHE_FSTRUCT(i) = privFont -> font_struct; + } + else + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentFontReconnect: failed\n"); + #endif + + nxagentCollectFailedFont(pFont, param1); + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentFontReconnect: reconnection of font [%s] failed.\n", + privFont -> fontName); + #endif + + nxagentSetReconnectError(FAILED_RESUME_FONTS_ALERT, + "Couldn't restore the font '%s'", privFont -> fontName); + + *pBool = False; + } + + return; +} + +static void nxagentFreeCacheBeforeReconnect(void) +{ + int i; + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + printFontCacheDump("nxagentFreeCacheBeforeReconnect"); + #endif + + for (i = 0; i < CACHE_INDEX; i++) + { + if (CACHE_FSTRUCT(i)) + { + nxagentFreeFont(CACHE_FSTRUCT(i)); + CACHE_FSTRUCT(i) = NULL; + } + } +} + +static void nxagentCleanCacheAfterReconnect(void) +{ + int i, j; + int real_size = CACHE_INDEX; + nxCacheFontEntryRecPtr swapEntryPtr; + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + printFontCacheDump("nxagentCleanCacheAfterReconnect"); + #endif + + for (i = 0; i < CACHE_INDEX; i++) + { + if(CACHE_FSTRUCT(i) == NULL) + { + XFree(CACHE_NAME(i)); + real_size--; + } + } + + for (i = 0; i < real_size; i++) + { + /* Find - first bad occurrence if exist. */ + while ((i < real_size) && CACHE_FSTRUCT(i)) i++; + + /* Really nothing more to do. */ + if (i == real_size) + break; + + /* + * Find - first good occurrence (moving backward from right end) entry in + * order to replace the bad one. + */ + for (j = CACHE_INDEX - 1; CACHE_FSTRUCT(j) == NULL; j--); + + /* + * Now we can swap the two entry + * and reduce the Cache index + */ + swapEntryPtr = CACHE_ENTRY(i); + CACHE_ENTRY(i) = CACHE_ENTRY(j); + CACHE_ENTRY(j) = swapEntryPtr; + } + + CACHE_INDEX = real_size; +} + +#ifdef NXAGENT_RECONNECT_FONT_DEBUG +static void printFontCacheDump(char* msg) +{ + int i; + + fprintf(stderr, "%s - begin -\n", msg); + + for (i = 0; i < CACHE_INDEX; i++) + { + if (CACHE_FSTRUCT(i)) + { + fprintf(stderr, "\tXID %lx - %s\n", CACHE_FSTRUCT(i) -> fid, CACHE_NAME(i)); + } + else + { + fprintf(stderr, "\tdestroyed - %s\n", CACHE_NAME(i)); + } + } + fprintf(stderr, "%s - end -\n", msg); +} +#endif + +Bool nxagentReconnectAllFonts(void *p0) +{ + int cid; + Bool fontSuccess = True; + + reconnectFlexibility = *((int *) p0); + + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_FONT_DEBUG) + fprintf(stderr, "nxagentReconnectAllFonts\n"); + #endif + + /* + * The resource type RT_NX_FONT is created on the + * server client only, so we can avoid to loop + * through all the clients. + */ + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_FONT, + (FindResType) nxagentFontReconnect, &fontSuccess); + + for (cid = 0; cid < MAXCLIENTS; cid++) + { + if (clients[cid]) + { + FindClientResourcesByType(clients[cid], RT_FONT, + (FindResType) nxagentFontReconnect, &fontSuccess); + } + } + + if (fontSuccess) + { + nxagentCleanCacheAfterReconnect(); + } + + return fontSuccess; +} + +static void nxagentFailedFontReconnect(FontPtr pFont, XID param1, void * param2) +{ + int i; + nxagentPrivFont *privFont; + Bool *pBool = (Bool*)param2; + + if (pFont == NULL) + return; + + privFont = nxagentFontPriv(pFont); + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentFailedFontReconnect: pFont %p - XID %lx - name %s\n", + (void*) pFont, (privFont -> font_struct) ? nxagentFont(pFont) : 0, + privFont -> fontName); + #endif + + for (i = 0; i < CACHE_INDEX; i++) + { + if (strcasecmp(CACHE_NAME(i), privFont -> fontName) == 0) + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "\tfound in cache"); + #endif + + if (!CACHE_FSTRUCT(i)) + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, " --- font struct not valid\n"); + #endif + + break; + } + + nxagentFontStruct(pFont) = CACHE_FSTRUCT(i); + + return; + } + } + + if (i == CACHE_INDEX) + { + FatalError("nxagentFailedFontReconnect: font not found in cache."); + } + + privFont -> font_struct = nxagentLoadQueryFont(nxagentDisplay, privFont -> fontName, pFont); + + if (privFont -> font_struct == NULL) + { + privFont -> font_struct = nxagentLoadBestQueryFont(nxagentDisplay, privFont -> fontName, pFont); + } + + if (privFont->font_struct != NULL) + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "\tXID %lx\n", privFont -> font_struct -> fid); + #endif + + CACHE_FSTRUCT(i) = privFont -> font_struct; + } + else + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentFailedFontReconnect: failed\n"); + #endif + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentFailedFontReconnect: reconnection of font [%s] failed.\n", + privFont -> fontName); + #endif + + nxagentSetReconnectError(FAILED_RESUME_FONTS_ALERT, + "Couldn't restore the font '%s'", privFont -> fontName); + + *pBool = False; + } + + return; +} + +static void nxagentFreeFailedToReconnectFonts() +{ + if (nxagentFailedToReconnectFonts.font != NULL) + { + free(nxagentFailedToReconnectFonts.font); + nxagentFailedToReconnectFonts.font = NULL; + } + + if (nxagentFailedToReconnectFonts.id != NULL) + { + free(nxagentFailedToReconnectFonts.id); + nxagentFailedToReconnectFonts.id = NULL; + } + + nxagentFailedToReconnectFonts.size = 0; + nxagentFailedToReconnectFonts.index = 0; +} + +Bool nxagentReconnectFailedFonts(void *p0) +{ + int i; + int attempt = 1; + const int maxAttempt = 5; + + char **fontPaths, **localFontPaths, **newFontPaths; + char fontServerPath[256] = ""; + int nPaths = 0; + + Bool repeat = True; + Bool fontSuccess = True; + + reconnectFlexibility = *((int *) p0); + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentReconnectFailedFonts: \n"); + #endif + + if (nxagentGetFontServerPath(fontServerPath) == False) + { + #ifdef WARNING + fprintf(stderr, "nxagentReconnectFailedFonts: WARNING! " + "Font server tunneling not retrieved.\n"); + #endif + } + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentReconnectFailedFonts: font server path [%s]\n", fontServerPath); + #endif + + fontPaths = XGetFontPath(nxagentDisplay, &nPaths); + + if ((newFontPaths = malloc((nPaths + 1) * sizeof(char *))) == NULL) + { + FatalError("nxagentReconnectFailedFonts: malloc failed."); + } + + memcpy(newFontPaths, fontPaths, nPaths * sizeof(char*)); + + localFontPaths = newFontPaths; + localFontPaths += nPaths; + *localFontPaths = fontServerPath; + + while(repeat) + { + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentReconnectFailedFonts: attempt [%d].\n", attempt); + #endif + + repeat = False; + + XSetFontPath(nxagentDisplay, newFontPaths, nPaths + 1); + nxagentFreeRemoteFontList(&nxagentRemoteFontList); + nxagentListRemoteFonts("*", nxagentMaxFontNames); + + for(i = 0; i < nxagentFailedToReconnectFonts.index; i++) + { + fontSuccess = True; + + if(nxagentFailedToReconnectFonts.font[i]) + { + nxagentFailedFontReconnect(nxagentFailedToReconnectFonts.font[i], + nxagentFailedToReconnectFonts.id[i], + &fontSuccess); + + if (fontSuccess) + { + nxagentFailedToReconnectFonts.font[i] = NULL; + } + else + { + repeat = True; + } + + } + } + + attempt++; + + if (attempt > maxAttempt) + { + nxagentFreeFailedToReconnectFonts(); + + XSetFontPath(nxagentDisplay, fontPaths, nPaths); + nxagentFreeRemoteFontList(&nxagentRemoteFontList); + nxagentListRemoteFonts("*", nxagentMaxFontNames); + + XFreeFontPath(fontPaths); + free(newFontPaths); + + return False; + } + } + + nxagentFreeFailedToReconnectFonts(); + + XSetFontPath(nxagentDisplay, fontPaths, nPaths); + + XFreeFontPath(fontPaths); + free(newFontPaths); + + nxagentCleanCacheAfterReconnect(); + + return True; +} + +Bool nxagentDisconnectAllFonts() +{ + int cid; + Bool fontSuccess = True; + + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_FONT_DEBUG) + fprintf(stderr, "nxagentDisconnectAllFonts\n"); + #endif + + nxagentFreeRemoteFontList(&nxagentRemoteFontList); + nxagentFreeCacheBeforeReconnect(); + + /* + * The resource type RT_NX_FONT is created on the + * server client only, so we can avoid to loop + * through all the clients. + */ + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_FONT, + (FindResType) nxagentFontDisconnect, &fontSuccess); + + for(cid = 0; cid < MAXCLIENTS; cid++) + { + if( clients[cid] && fontSuccess ) + { + FindClientResourcesByType(clients[cid], RT_FONT, + (FindResType) nxagentFontDisconnect, &fontSuccess); + } + } + + return True; +} + +static Bool nxagentGetFontServerPath(char * fontServerPath) +{ + char path[256]; + + if (NXGetFontParameters(nxagentDisplay, 256, path) == True) + { + if (*path != '\0') + { + strncpy(fontServerPath, path + 1, *path); + + *(fontServerPath + *path) = '\0'; + + #ifdef TEST + fprintf(stderr, "nxagentGetFontServerPath: Got path [%s].\n", + fontServerPath); + #endif + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentGetFontServerPath: WARNING! Font server tunneling not enabled.\n"); + #endif + + return False; + } + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentGetFontServerPath: WARNING! Failed to get path for font server tunneling.\n"); + #endif + + return False; + } + + return True; +} + +void nxagentVerifyDefaultFontPath(void) +{ + struct stat dirStat; + static char *fontPath; + + #ifdef TEST + fprintf(stderr, "nxagentVerifyDefaultFontPath: Going to search for one or more valid font paths.\n"); + #endif + + fontPath = malloc(strlen(defaultFontPath) + 1); + + if (fontPath == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentVerifyDefaultFontPath: WARNING! Unable to allocate memory for a new font path. " + "Using the default font path [%s].\n", validateString(defaultFontPath)); + #endif + + return; + } + + /* + * Set the default font path as the first choice. + */ + + strcpy(fontPath, defaultFontPath); + + if (stat(NXAGENT_DEFAULT_FONT_DIR, &dirStat) == 0 && + S_ISDIR(dirStat.st_mode) != 0) + { + /* + * Let's use the old "/usr/share/nx/fonts" style. + */ + + #ifdef TEST + fprintf(stderr, "nxagentVerifyDefaultFontPath: Assuming fonts in directory [%s].\n", + validateString(NXAGENT_DEFAULT_FONT_DIR)); + #endif + + if (*fontPath != '\0') + { + fontPath = realloc(fontPath, strlen(fontPath) + strlen(NXAGENT_DEFAULT_FONT_PATH) + 2); + strcat(fontPath, ","); + } + else + { + fontPath = realloc(fontPath, strlen(fontPath) + strlen(NXAGENT_DEFAULT_FONT_PATH) + 1); + } + + strcat(fontPath, NXAGENT_DEFAULT_FONT_PATH); + } + + if (stat(NXAGENT_ALTERNATE_FONT_DIR, &dirStat) == 0 && + S_ISDIR(dirStat.st_mode) != 0) + { + /* + * Let's use the new "/usr/share/X11/fonts" path. + */ + + #ifdef TEST + fprintf(stderr, "nxagentVerifyDefaultFontPath: Assuming fonts in directory [%s].\n", + validateString(NXAGENT_ALTERNATE_FONT_DIR)); + #endif + + if (*fontPath != '\0') + { + fontPath = realloc(fontPath, strlen(fontPath) + strlen(NXAGENT_ALTERNATE_FONT_PATH) + 2); + strcat(fontPath, ","); + } + else + { + fontPath = realloc(fontPath, strlen(fontPath) + strlen(NXAGENT_ALTERNATE_FONT_PATH) + 1); + } + + strcat(fontPath, NXAGENT_ALTERNATE_FONT_PATH); + } + + if (stat(NXAGENT_ALTERNATE_FONT_DIR_2, &dirStat) == 0 && + S_ISDIR(dirStat.st_mode) != 0) + { + /* + * Let's use the "/usr/share/fonts/X11" path. + */ + + #ifdef TEST + fprintf(stderr, "nxagentVerifyDefaultFontPath: Assuming fonts in directory [%s].\n", + validateString(NXAGENT_ALTERNATE_FONT_DIR_2)); + #endif + + if (*fontPath != '\0') + { + fontPath = realloc(fontPath, strlen(fontPath) + strlen(NXAGENT_ALTERNATE_FONT_PATH_2) + 2); + strcat(fontPath, ","); + } + else + { + fontPath = realloc(fontPath, strlen(fontPath) + strlen(NXAGENT_ALTERNATE_FONT_PATH_2) + 1); + } + + strcat(fontPath, NXAGENT_ALTERNATE_FONT_PATH_2); + } + + if (stat(NXAGENT_ALTERNATE_FONT_DIR_3, &dirStat) == 0 && + S_ISDIR(dirStat.st_mode) != 0) + { + /* + * Let's use the "/usr/X11R6/lib/X11/fonts" path. + */ + + #ifdef TEST + fprintf(stderr, "nxagentVerifyDefaultFontPath: Assuming fonts in directory [%s].\n", + validateString(NXAGENT_ALTERNATE_FONT_DIR_3)); + #endif + + if (*fontPath != '\0') + { + fontPath = realloc(fontPath, strlen(fontPath) + strlen(NXAGENT_ALTERNATE_FONT_PATH_3) + 2); + strcat(fontPath, ","); + } + else + { + fontPath = realloc(fontPath, strlen(fontPath) + strlen(NXAGENT_ALTERNATE_FONT_PATH_3) + 1); + } + + strcat(fontPath, NXAGENT_ALTERNATE_FONT_PATH_3); + } + if (*fontPath == '\0') + { + #ifdef WARNING + fprintf(stderr, "nxagentVerifyDefaultFontPath: WARNING! Can't find a valid font directory.\n"); + + fprintf(stderr, "nxagentVerifyDefaultFontPath: WARNING! Using font path [%s].\n", + validateString(defaultFontPath)); + #endif + } + else + { + defaultFontPath = fontPath; + + #ifdef TEST + fprintf(stderr, "nxagentVerifyDefaultFontPath: Using font path [%s].\n", + validateString(defaultFontPath)); + #endif + } + + return; +} + +XFontStruct* nxagentLoadQueryFont(register Display *dpy, char *name, FontPtr pFont) +{ + XFontStruct* fs; + xCharInfo *xcip; + + fs = (XFontStruct *) malloc (sizeof (XFontStruct)); + + if (fs == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentLoadQueryFont: WARNING! Failed allocation of XFontStruct.\n"); + #endif + + return (XFontStruct *)NULL; + } + + #ifdef NXAGENT_RECONNECT_FONT_DEBUG + fprintf(stderr, "nxagentLoadQueryFont: Looking for font '%s'.\n", name); + #endif + + if (nxagentFontLookUp(name) == 0) + { + #ifdef DEBUG + fprintf(stderr, "nxagentLoadQueryFont: WARNING! Font not found '%s'.\n", name); + #endif + + free(fs); + + return (XFontStruct *) NULL; + } + + fs -> ext_data = NULL; /* Hook for extension to hang data.*/ + fs -> fid = XLoadFont(dpy, name); /* Font id for this font. */ + fs -> direction = pFont->info.drawDirection; /* Hint about the direction font is painted. */ + fs -> min_char_or_byte2 = pFont->info.firstCol; /* First character. */ + fs -> max_char_or_byte2 = pFont->info.lastCol; /* Last character. */ + fs -> min_byte1 = pFont->info.firstRow; /* First row that exists. */ + fs -> max_byte1 = pFont->info.lastRow; /* Last row that exists. */ + fs -> all_chars_exist = pFont->info.allExist; /* Flag if all characters have nonzero size. */ + fs -> default_char = pFont->info.defaultCh; /* Char to print for undefined character. */ + fs -> n_properties = pFont->info.nprops; /* How many properties there are. */ + + /* + * If no properties defined for the font, then it is bad + * font, but shouldn't try to read nothing. + */ + + if (fs -> n_properties > 0) + { + register long nbytes; + + nbytes = pFont -> info.nprops * sizeof(XFontProp); + fs -> properties = (XFontProp *) malloc((unsigned) nbytes); + + if (fs -> properties == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentLoadQueryFont: WARNING! Failed allocation of XFontProp."); + #endif + + free((char *) fs); + return (XFontStruct *) NULL; + } + + memmove(fs -> properties, pFont -> info.props, nbytes); + } + + xcip = (xCharInfo *) &pFont -> info.ink_minbounds; + + fs -> min_bounds.lbearing = cvtINT16toShort(xcip -> leftSideBearing); + fs -> min_bounds.rbearing = cvtINT16toShort(xcip -> rightSideBearing); + fs -> min_bounds.width = cvtINT16toShort(xcip -> characterWidth); + fs -> min_bounds.ascent = cvtINT16toShort(xcip -> ascent); + fs -> min_bounds.descent = cvtINT16toShort(xcip -> descent); + fs -> min_bounds.attributes = xcip -> attributes; + + xcip = (xCharInfo *) &pFont -> info.ink_maxbounds; + + fs -> max_bounds.lbearing = cvtINT16toShort(xcip -> leftSideBearing); + fs -> max_bounds.rbearing = cvtINT16toShort(xcip -> rightSideBearing); + fs -> max_bounds.width = cvtINT16toShort(xcip -> characterWidth); + fs -> max_bounds.ascent = cvtINT16toShort(xcip -> ascent); + fs -> max_bounds.descent = cvtINT16toShort(xcip -> descent); + fs -> max_bounds.attributes = xcip -> attributes; + + fs -> per_char = NULL; /* First_char to last_char information. */ + fs -> ascent = pFont->info.fontAscent; /* Logical extent above baseline for spacing. */ + fs -> descent = pFont->info.fontDescent; /* Logical decent below baseline for spacing. */ + + return fs; +} + +int nxagentFreeFont(XFontStruct *fs) +{ + + if (fs -> per_char) + { + #ifdef USE_XF86BIGFONT + _XF86BigfontFreeFontMetrics(fs); + #else + free ((char *) fs->per_char); + #endif + } + + if (fs -> properties) + { + free (fs->properties); + } + + XFree(fs); + + return 1; +} + + +int nxagentSplitString(char *string, char *fields[], int nfields, char *sep) +{ + int seplen; + int fieldlen; + int last; + int len; + int i; + + char *current; + char *next; + + seplen = strlen(sep); + len = strlen(string); + + current = string; + + i = 0; + last = 0; + + for (;;) + { + next = NULL; + + if (current < string + len) + { + next = strstr(current, sep); + } + + if (next == NULL) + { + next = string + len; + last = 1; + } + + fieldlen = next - current; + + if (i < nfields) + { + fields[i] = (char *) malloc(fieldlen + 1); + strncpy(fields[i], current, fieldlen); + *(fields[i] + fieldlen) = 0; + } + else + { + fields[i] = NULL; + } + + current = next + seplen; + + i++; + + if (last == 1) + { + break; + } + } + + return i; +} + +char *nxagentMakeScalableFontName(const char *fontName, int scalableResolution) +{ + char *scalableFontName; + const char *s; + int len; + int field; + + len = strlen(fontName) + 1; + + scalableFontName = malloc(len); + + if (scalableFontName == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentMakeScalableFontName: PANIC! malloc() failed.\n"); + #endif + + return NULL; + } + + scalableFontName[0] = 0; + + if (*fontName != '-') + { + goto MakeScalableFontNameError; + } + + s = fontName; + + field = 0; + + while (s != NULL) + { + s = strchr(s + 1, '-'); + + if (s != NULL) + { + if (field == 6 || field == 7 || field == 11) + { + /* + * PIXEL_SIZE || POINT_SIZE || AVERAGE_WIDTH + */ + + strcat(scalableFontName, "-0"); + } + else if (scalableResolution == 1 && (field == 8 || field == 9)) + { + /* + * RESOLUTION_X || RESOLUTION_Y + */ + + strcat(scalableFontName, "-0"); + } + else + { + strncat(scalableFontName, fontName, s - fontName); + } + + fontName = s; + } + else + { + strcat(scalableFontName, fontName); + } + + field++; + } + + if (field != 14) + { + goto MakeScalableFontNameError; + } + + return scalableFontName; + +MakeScalableFontNameError: + + free(scalableFontName); + + #ifdef DEBUG + fprintf(stderr, "nxagentMakeScalableFontName: Invalid font name.\n"); + #endif + + return NULL; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Font.h b/nx-X11/programs/Xserver/hw/nxagent/Font.h new file mode 100644 index 000000000..c5b236562 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Font.h @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Font_H__ +#define __Font_H__ + +#include <X11/fonts/fontstruct.h> +#include "resource.h" + +extern RESTYPE RT_NX_FONT; + +extern int nxagentFontPrivateIndex; + +typedef struct +{ + XFontStruct *font_struct; + char fontName[256]; + XID mirrorID; +} nxagentPrivFont; + +extern const int nxagentMaxFontNames; + +#define nxagentFontPriv(pFont) \ + ((nxagentPrivFont *)FontGetPrivate(pFont, nxagentFontPrivateIndex)) + +#define nxagentFontStruct(pFont) (nxagentFontPriv(pFont)->font_struct) + +#define nxagentFont(pFont) (nxagentFontStruct(pFont)->fid) + +Bool nxagentRealizeFont(ScreenPtr pScreen, FontPtr pFont); +Bool nxagentUnrealizeFont(ScreenPtr pScreen, FontPtr pFont); + +void nxagentFreeFontCache(void); + +void nxagentListRemoteFonts(const char *searchPattern, const int maxNames); +int nxagentFontLookUp(const char *name); +Bool nxagentFontFind(const char *name, int *pos); +void nxagentListRemoteAddName(const char *name, int status); + +int nxagentDestroyNewFontResourceType(void * p, XID id); + +Bool nxagentDisconnectAllFonts(void); +Bool nxagentReconnectAllFonts(void *p0); + +void nxagentVerifyDefaultFontPath(void); + +int nxagentSplitString(char *string, char *fields[], int nfields, char *sep); + +#endif /* __Font_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/GC.c b/nx-X11/programs/Xserver/hw/nxagent/GC.c new file mode 100644 index 000000000..abe66602a --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/GC.c @@ -0,0 +1,1717 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include "X.h" +#include "Xproto.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "scrnintstr.h" +#include "dixstruct.h" +#include <X11/fonts/fontstruct.h> +#include "mistruct.h" +#include "region.h" + +#include "Agent.h" + +#include "Display.h" +#include "GCs.h" +#include "GCOps.h" +#include "Image.h" +#include "Drawable.h" +#include "Pixmaps.h" +#include "Font.h" +#include "Colormap.h" +#include "Trap.h" +#include "Screen.h" +#include "Pixels.h" + +#include "../../fb/fb.h" + +RESTYPE RT_NX_GC; +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +int nxagentGCPrivateIndex; + +nxagentGraphicContextsPtr nxagentGraphicContexts; +int nxagentGraphicContextsSize; + +void nxagentDisconnectGraphicContexts(void); +GCPtr nxagentCreateGraphicContext(int depth); + +static void nxagentReconnectGC(void*, XID, void*); +static void nxagentReconnectClip(GCPtr, int, void *, int); +static int nxagentCompareRegions(RegionPtr, RegionPtr); + +struct nxagentGCRec +{ + GCPtr pGC; + XlibGC gc; + struct nxagentGCRec *next; +}; + +static struct +{ + struct nxagentGCRec *first; + struct nxagentGCRec *last; + int size; +} nxagentGCList = { NULL, NULL, 0 }; + +static struct nxagentGCRec *nxagentGetFirstGC(void); + +static void nxagentRestoreGCList(void); + +static GCFuncs nxagentFuncs = +{ + nxagentValidateGC, + nxagentChangeGC, + nxagentCopyGC, + nxagentDestroyGC, + nxagentChangeClip, + nxagentDestroyClip, + nxagentCopyClip, +}; + +static GCOps nxagentOps = +{ + nxagentFillSpans, + nxagentSetSpans, + nxagentPutImage, + nxagentCopyArea, + nxagentCopyPlane, + nxagentPolyPoint, + nxagentPolyLines, + nxagentPolySegment, + nxagentPolyRectangle, + nxagentPolyArc, + nxagentFillPolygon, + nxagentPolyFillRect, + nxagentPolyFillArc, + nxagentPolyText8, + nxagentPolyText16, + nxagentImageText8, + nxagentImageText16, + nxagentImageGlyphBlt, + nxagentPolyGlyphBlt, + nxagentPushPixels +}; + +Bool nxagentCreateGC(GCPtr pGC) +{ + FbGCPrivPtr pPriv; + + pGC->clientClipType = CT_NONE; + pGC->clientClip = NULL; + + pGC->funcs = &nxagentFuncs; + pGC->ops = &nxagentOps; + + pGC->miTranslate = 1; + + if (pGC -> stipple && !nxagentPixmapIsVirtual(pGC -> stipple)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentCreateGC: GC at [%p] got real stipple at [%p] switched to virtual.\n", + (void*)pGC, (void*)pGC -> stipple); + #endif + + pGC -> stipple = nxagentVirtualPixmap(pGC -> stipple); + } + + /* + * We create the GC based on the default + * drawables. The proxy knows this and + * optimizes the encoding of the create + * GC message to include the id of the + * drawable in the checksum. + */ + + nxagentGCPriv(pGC)->gc = XCreateGC(nxagentDisplay, + nxagentDefaultDrawables[pGC->depth], + 0L, NULL); + + #ifdef TEST + fprintf(stderr, "nxagentCreateGC: GC [%p]\n", (void *) pGC); + #endif + + pPriv = (pGC)->devPrivates[fbGCPrivateIndex].ptr; + + fbGetRotatedPixmap(pGC) = 0; + fbGetExpose(pGC) = 1; + fbGetFreeCompClip(pGC) = 0; + fbGetCompositeClip(pGC) = 0; + + pPriv->bpp = BitsPerPixel (pGC->depth); + + nxagentGCPriv(pGC)->nClipRects = 0; + + memset(&(nxagentGCPriv(pGC) -> lastServerValues), 0, sizeof(XGCValues)); + + /* + * Init to default GC values. + */ + + nxagentGCPriv(pGC) -> lastServerValues.background = 1; + + nxagentGCPriv(pGC) -> lastServerValues.plane_mask = ~0; + + nxagentGCPriv(pGC) -> lastServerValues.graphics_exposures = 1; + + nxagentGCPriv(pGC) -> lastServerValues.dashes = 4; + + nxagentGCPriv(pGC) -> mid = FakeClientID(serverClient -> index); + + nxagentGCPriv(pGC) -> pPixmap = NULL; + + AddResource(nxagentGCPriv(pGC) -> mid, RT_NX_GC, (void *) pGC); + + return True; +} + +void nxagentValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + PixmapPtr lastTile, lastStipple; + + DrawablePtr pVirtual = (pDrawable -> type == DRAWABLE_PIXMAP) ? + nxagentVirtualDrawable(pDrawable) : + pDrawable; + + #ifdef TEST + fprintf(stderr, "nxagentValidateGC: Going to validate GC at [%p] for drawable at [%p] with changes [%lx].\n", + (void *) pGC, (void *) pDrawable, changes); + #endif + + pGC->lastWinOrg.x = pDrawable->x; + pGC->lastWinOrg.y = pDrawable->y; + + if (!pGC -> tileIsPixel && !nxagentPixmapIsVirtual(pGC -> tile.pixmap)) + { + pGC -> tile.pixmap = nxagentVirtualPixmap(pGC -> tile.pixmap); + } + + lastTile = pGC -> tile.pixmap; + + lastStipple = pGC->stipple; + + if (lastStipple) + { + pGC->stipple = nxagentVirtualPixmap(pGC->stipple); + } + + #ifdef TEST + fprintf(stderr, "nxagentValidateGC: Drawable at [%p] has type [%s] virtual [%p] bits per pixel [%d].\n", + (void *) pDrawable, (pDrawable -> type == DRAWABLE_PIXMAP) ? "PIXMAP" : "WINDOW", + (void *) pVirtual, pVirtual -> bitsPerPixel); + #endif + + if (pVirtual -> bitsPerPixel == 0) + { + /* + * Don't enter fbValidateGC() with 0 bpp + * or agent will block in a endless loop. + */ + + #ifdef WARNING + fprintf(stderr, "nxagentValidateGC: WARNING! Virtual drawable at [%p] has invalid bits per pixel.\n", + (void *) pVirtual); + + fprintf(stderr, "nxagentValidateGC: WARNING! While validating GC at [%p] for drawable at [%p] with changes [%lx].\n", + (void *) pGC, (void *) pDrawable, changes); + + fprintf(stderr, "nxagentValidateGC: WARNING! Bad drawable at [%p] has type [%s] virtual [%p] bits per pixel [%d].\n", + (void *) pDrawable, (pDrawable -> type == DRAWABLE_PIXMAP) ? "PIXMAP" : "WINDOW", + (void *) pVirtual, pVirtual -> bitsPerPixel); + #endif + } + else + { + fbValidateGC(pGC, changes, pVirtual); + } + + if (pGC->tile.pixmap != lastTile) + { + #ifdef WARNING + fprintf(stderr, "nxagentValidateGC: WARNING! Transforming pixmap at [%p] virtual at [%p] " + "in virtual pixmap.\n", (void *) nxagentPixmapPriv(pGC -> tile.pixmap) -> pRealPixmap, + (void *) nxagentPixmapPriv(pGC -> tile.pixmap) -> pRealPixmap); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentValidateGC: GC [%p] new tile [%p] from fb set as virtual\n", + (void *) pGC, (void *) pGC->tile.pixmap); + #endif + + nxagentPixmapIsVirtual(pGC->tile.pixmap) = True; + nxagentRealPixmap(pGC->tile.pixmap) = nxagentRealPixmap(lastTile); + + if (nxagentRealPixmap(lastTile)) + { + nxagentPixmapPriv(nxagentRealPixmap(lastTile))->pVirtualPixmap = pGC->tile.pixmap; + } + } + + pGC->stipple = lastStipple; +} + +void nxagentChangeGC(GCPtr pGC, unsigned long mask) +{ + #ifdef TEST + static int nDiscarded; + #endif + + XGCValues values; + + int changeFlag = 0; + + if (mask & GCFunction) + { + values.function = pGC->alu; + + changeFlag |= nxagentTestGC(values.function, function); + } + + if (mask & GCPlaneMask) + { + values.plane_mask = pGC->planemask; + + changeFlag += nxagentTestGC(values.plane_mask, plane_mask); + } + + if (mask & GCForeground) + { + values.foreground = nxagentPixel(pGC->fgPixel); + + changeFlag += nxagentTestGC(values.foreground, foreground); + } + + if (mask & GCBackground) + { + values.background = nxagentPixel(pGC->bgPixel); + + changeFlag += nxagentTestGC(values.background, background); + } + + if (mask & GCLineWidth) + { + values.line_width = pGC->lineWidth; + + changeFlag += nxagentTestGC(values.line_width, line_width); + } + + if (mask & GCLineStyle) + { + values.line_style = pGC->lineStyle; + + changeFlag += nxagentTestGC(values.line_style, line_style); + } + + if (mask & GCCapStyle) + { + values.cap_style = pGC->capStyle; + + changeFlag += nxagentTestGC(values.cap_style, cap_style); + } + + if (mask & GCJoinStyle) + { + values.join_style = pGC->joinStyle; + + changeFlag += nxagentTestGC(values.join_style, join_style); + } + + if (mask & GCFillStyle) + { + values.fill_style = pGC->fillStyle; + + changeFlag += nxagentTestGC(values.fill_style, fill_style); + } + + if (mask & GCFillRule) + { + values.fill_rule = pGC->fillRule; + + changeFlag += nxagentTestGC(values.fill_rule, fill_rule); + } + + if (mask & GCTile) + { + if (pGC->tileIsPixel) + { + mask &= ~GCTile; + } + else + { + if (nxagentDrawableStatus((DrawablePtr) pGC -> tile.pixmap) == NotSynchronized && + nxagentGCTrap == 0) + { + /* + * If the tile is corrupted and is not too + * much large, it can be synchronized imme- + * diately. In the other cases, the tile is + * cleared with a solid color to become usa- + * ble. This approach should solve the high + * delay on slow links waiting for a back- + * ground tile to be synchronized. + */ + + if (nxagentOption(DeferLevel) >= 2 && + (pGC -> tile.pixmap -> drawable.width > 240 || + pGC -> tile.pixmap -> drawable.height > 240)) + { + #ifdef TEST + fprintf(stderr, "nxagentChangeGC: WARNING! Going to fill with solid color the corrupted tile at [%p] " + "for GC at [%p] with size [%dx%d].\n", (void *) pGC -> tile.pixmap, (void *)pGC, + ((DrawablePtr) pGC -> tile.pixmap) -> width, ((DrawablePtr) pGC -> tile.pixmap) -> height); + #endif + + nxagentFillRemoteRegion((DrawablePtr) pGC -> tile.pixmap, nxagentCorruptedRegion((DrawablePtr) pGC -> tile.pixmap)); + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentChangeGC: WARNING! Synchronizing GC at [%p] due the tile at [%p] with size [%dx%d].\n", + (void *)pGC, (void *)pGC -> tile.pixmap, ((DrawablePtr) pGC -> tile.pixmap) -> width, + ((DrawablePtr) pGC -> tile.pixmap) -> height); + #endif + + nxagentSynchronizeDrawable((DrawablePtr) pGC -> tile.pixmap, DO_WAIT, NEVER_BREAK, NULL); + } + } + + values.tile = nxagentPixmap(pGC->tile.pixmap); + + pGC->tile.pixmap = nxagentVirtualPixmap(pGC->tile.pixmap); + + #ifdef TEST + fprintf(stderr, "nxagentChangeGC: New tile on GC [%p] tile is [%p]\n", + (void *) pGC, (void *) pGC->tile.pixmap); + #endif + + changeFlag += nxagentTestGC(values.tile, tile); + } + } + + if (mask & GCStipple) + { + if (nxagentDrawableStatus((DrawablePtr) pGC -> stipple) == NotSynchronized && + nxagentGCTrap == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentChangeGC: WARNING! Synchronizing GC at [%p] due the stipple at [%p].\n", + (void *)pGC, (void *)pGC -> stipple); + #endif + + nxagentSynchronizeDrawable((DrawablePtr) pGC -> stipple, DO_WAIT, NEVER_BREAK, NULL); + } + + values.stipple = nxagentPixmap(pGC->stipple); + + pGC->stipple = nxagentVirtualPixmap(pGC->stipple); + + #ifdef TEST + fprintf(stderr, "nxagentChangeGC: New stipple on GC [%p] stipple is [%p]\n", + (void *) pGC, (void *) pGC->stipple); + #endif + + changeFlag += nxagentTestGC(values.stipple, stipple); + } + + if (mask & GCTileStipXOrigin) + { + values.ts_x_origin = pGC->patOrg.x; + + changeFlag += nxagentTestGC(values.ts_x_origin, ts_x_origin); + } + + if (mask & GCTileStipYOrigin) + { + values.ts_y_origin = pGC->patOrg.y; + + changeFlag += nxagentTestGC(values.ts_y_origin, ts_y_origin); + } + + if (mask & GCFont) + { + if (!nxagentFontStruct(pGC -> font)) + { + mask &= ~GCFont; + } + else + { + values.font = nxagentFont(pGC->font); + + changeFlag += nxagentTestGC(values.font, font); + } + } + + if (mask & GCSubwindowMode) + { + values.subwindow_mode = pGC->subWindowMode; + + changeFlag += nxagentTestGC(values.subwindow_mode, subwindow_mode); + } + + if (mask & GCGraphicsExposures) + { + values.graphics_exposures = pGC->graphicsExposures; + + changeFlag += nxagentTestGC(values.graphics_exposures, graphics_exposures); + } + + if (mask & GCClipXOrigin) + { + values.clip_x_origin = pGC->clipOrg.x; + + changeFlag += nxagentTestGC(values.clip_x_origin, clip_x_origin); + } + + if (mask & GCClipYOrigin) + { + values.clip_y_origin = pGC->clipOrg.y; + + changeFlag += nxagentTestGC(values.clip_y_origin, clip_y_origin); + } + + if (mask & GCClipMask) + { + /* + * This is handled in the change clip. + */ + + mask &= ~GCClipMask; + } + + if (mask & GCDashOffset) + { + values.dash_offset = pGC->dashOffset; + + changeFlag += nxagentTestGC(values.dash_offset, dash_offset); + } + + if (mask & GCDashList) + { + mask &= ~GCDashList; + + if (nxagentGCTrap == 0) + { + XSetDashes(nxagentDisplay, nxagentGC(pGC), + pGC->dashOffset, (char *)pGC->dash, pGC->numInDashList); + } + } + + if (mask & GCArcMode) + { + values.arc_mode = pGC->arcMode; + + changeFlag += nxagentTestGC(values.arc_mode, arc_mode); + } + + if (nxagentGCTrap == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentChangeGC: Skipping change of GC at [%p] on the real X server.\n", + (void *) pGC); + #endif + + return; + } + + if (mask && changeFlag) + { + XChangeGC(nxagentDisplay, nxagentGC(pGC), mask, &values); + } + #ifdef TEST + else if (mask) + { + fprintf(stderr, "nxagentChangeGC: Discarded [%d] Mask [%lu]\n", ++nDiscarded, mask); + } + #endif +} + +void nxagentCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) +{ + #ifdef TEST + fprintf(stderr, "nxagentCopyGC: Copying the GC with source at [%p] destination " + "at [%p] mask [%lu].\n", pGCSrc, pGCDst, mask); + #endif + + /* + * The MI function doesn't do anything. + * + * miCopyGC(pGCSrc, mask, pGCDst); + */ + + XCopyGC(nxagentDisplay, nxagentGC(pGCSrc), mask, nxagentGC(pGCDst)); + + /* + * Copy the private foreground field + * of the GC if GCForeground is set. + */ + + nxagentCopyGCPriv(GCForeground,foreground,pGCSrc,mask,pGCDst); +} + +void nxagentDestroyGC(GCPtr pGC) +{ + #ifdef TEST + fprintf(stderr, "nxagentDestroyGC: GC at [%p].\n", (void *) pGC); + #endif + + if (nxagentGCPriv(pGC) -> mid != 0) + { + FreeResource(nxagentGCPriv(pGC) -> mid, RT_NONE); + } + + XFreeGC(nxagentDisplay, nxagentGC(pGC)); + + miDestroyGC(pGC); +} + +void nxagentChangeClip(GCPtr pGC, int type, void * pValue, int nRects) +{ + int i, size; + BoxPtr pBox; + XRectangle *pRects; + int clipsMatch = 0; + + #ifdef TEST + fprintf(stderr, "nxagentChangeClip: Going to change clip on GC [%p]\n", + (void *) pGC); + #endif + + switch (type) + { + case CT_NONE: + { + clipsMatch = (pGC -> clientClipType == None); + + break; + } + case CT_REGION: + { + clipsMatch = nxagentCompareRegions(pGC -> clientClip, (RegionPtr) pValue); + + break; + } + case CT_UNSORTED: + case CT_YSORTED: + case CT_YXSORTED: + case CT_YXBANDED: + { + RegionPtr pReg = RegionFromRects(nRects, (xRectangle *)pValue, type); + + clipsMatch = nxagentCompareRegions(pGC -> clientClip, pReg); + + RegionDestroy(pReg); + + break; + } + default: + { + clipsMatch = 0; + + break; + } + } + + nxagentDestroyClipHelper(pGC); + + #ifdef TEST + fprintf(stderr, "nxagentChangeClip: Type [%d] regions clipsMatch [%d].\n", + type, clipsMatch); + #endif + + switch (type) + { + case CT_NONE: + { + if (clipsMatch == 0 && nxagentGCTrap == 0) + { + XSetClipMask(nxagentDisplay, nxagentGC(pGC), None); + } + + break; + } + case CT_REGION: + { + if (clipsMatch == 0 && nxagentGCTrap == 0) + { + nRects = RegionNumRects((RegionPtr)pValue); + size = nRects * sizeof(*pRects); + pRects = (XRectangle *) malloc(size); + pBox = RegionRects((RegionPtr)pValue); + + for (i = nRects; i-- > 0;) + { + pRects[i].x = pBox[i].x1; + pRects[i].y = pBox[i].y1; + pRects[i].width = pBox[i].x2 - pBox[i].x1; + pRects[i].height = pBox[i].y2 - pBox[i].y1; + } + + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), pGC -> clipOrg.x, pGC -> clipOrg.y, + pRects, nRects, Unsorted); + free((char *) pRects); + } + + break; + } + case CT_PIXMAP: + { + if (nxagentGCTrap == 0) + { + XSetClipMask(nxagentDisplay, nxagentGC(pGC), + nxagentPixmap((PixmapPtr)pValue)); + } + + pGC->clientClip = (void *) (*pGC->pScreen->BitmapToRegion)((PixmapPtr) pValue); + + nxagentGCPriv(pGC)->pPixmap = (PixmapPtr)pValue; + + pValue = pGC->clientClip; + + type = CT_REGION; + + break; + } + case CT_UNSORTED: + { + if (clipsMatch == 0 && nxagentGCTrap == 0) + { + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, Unsorted); + } + + break; + } + case CT_YSORTED: + { + if (clipsMatch == 0 && nxagentGCTrap == 0) + { + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, YSorted); + } + + break; + } + case CT_YXSORTED: + { + if (clipsMatch == 0 && nxagentGCTrap == 0) + { + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, YXSorted); + } + + break; + } + case CT_YXBANDED: + { + if (clipsMatch == 0 && nxagentGCTrap == 0) + { + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, YXBanded); + } + + break; + } + } + + switch(type) + { + case CT_UNSORTED: + case CT_YSORTED: + case CT_YXSORTED: + case CT_YXBANDED: + { + /* + * Other parts of the server can only + * deal with CT_NONE, CT_PIXMAP and + * CT_REGION client clips. + */ + + pGC->clientClip = (void *) RegionFromRects(nRects, + (xRectangle *)pValue, type); + free(pValue); + + pValue = pGC->clientClip; + + type = CT_REGION; + + break; + } + default: + { + break; + } + } + + pGC->clientClipType = type; + pGC->clientClip = pValue; + + nxagentGCPriv(pGC)->nClipRects = nRects; +} + +void nxagentDestroyClip(GCPtr pGC) +{ + miDestroyClip(pGC); + + if (pGC->clientClipType == CT_PIXMAP) + { + (*pGC->pScreen->DestroyPixmap)((PixmapPtr) (pGC->clientClip)); + } + + nxagentDestroyClipHelper(pGC); + + if (nxagentGCTrap == 0) + { + XSetClipMask(nxagentDisplay, nxagentGC(pGC), None); + } + + pGC->clientClipType = CT_NONE; + pGC->clientClip = NULL; + + nxagentGCPriv(pGC)->nClipRects = 0; +} + +void nxagentDestroyClipHelper(GCPtr pGC) +{ + switch (pGC->clientClipType) + { + default: + case CT_NONE: + break; + case CT_REGION: + RegionDestroy(pGC->clientClip); + break; + case CT_PIXMAP: + nxagentDestroyPixmap((PixmapPtr)pGC->clientClip); + break; + } + + if (nxagentGCPriv(pGC)->pPixmap != NULL) + { + nxagentDestroyPixmap(nxagentGCPriv(pGC)->pPixmap); + nxagentGCPriv(pGC)->pPixmap = NULL; + } +} + +void nxagentCopyClip(GCPtr pGCDst, GCPtr pGCSrc) +{ + RegionPtr pRgn; + + #ifdef TEST + fprintf(stderr, "nxagentCopyClip: Going to copy clip from GC [%p] to GC [%p]\n", + (void *) pGCDst, (void *) pGCSrc); + #endif + + switch (pGCSrc->clientClipType) + { + case CT_REGION: + if (nxagentGCPriv(pGCSrc)->pPixmap == NULL) + { + pRgn = RegionCreate(NULL, 1); + RegionCopy(pRgn, pGCSrc->clientClip); + nxagentChangeClip(pGCDst, CT_REGION, pRgn, 0); + } + else + { + nxagentGCPriv(pGCSrc)->pPixmap->refcnt++; + + nxagentChangeClip(pGCDst, CT_PIXMAP, nxagentGCPriv(pGCSrc)->pPixmap, 0); + } + break; + case CT_PIXMAP: + + #ifdef WARNING + fprintf(stderr, "nxagentCopyClip: WARNING! Not incrementing counter for virtual pixmap at [%p].\n", + (void *) nxagentVirtualPixmap((PixmapPtr) pGCSrc->clientClip)); + #endif + + ((PixmapPtr) pGCSrc->clientClip)->refcnt++; + + nxagentChangeClip(pGCDst, CT_PIXMAP, pGCSrc->clientClip, 0); + + break; + + case CT_NONE: + nxagentDestroyClip(pGCDst); + break; + + } +} + +static struct nxagentGCRec *nxagentGetFirstGC() +{ + struct nxagentGCRec *tmp = nxagentGCList.first; + + if (nxagentGCList.size) + { + nxagentGCList.first = nxagentGCList.first -> next; + nxagentGCList.size--; + + if (nxagentGCList.size == 0) + { + nxagentGCList.last = NULL; + } + } + + return tmp; +} + +static void nxagentFreeGCRec(struct nxagentGCRec *t) +{ + #ifdef TEST + fprintf(stderr, "nxagentFreeGCRec: Freeing record at %p GC freed at %p.\n", + (void *) t, (void *) t -> gc); + #endif + + free(t -> gc); + + free(t); +} + +static void nxagentRestoreGCRec(struct nxagentGCRec *t) +{ + #ifdef TEST + fprintf(stderr, "nxagentRestoreGCRec: Freeing record at %p GC freed at %p.\n", + (void*)t, (void*)t -> gc); + #endif + + if (nxagentGC(t -> pGC)) + { + free(nxagentGC(t -> pGC)); + } + + nxagentGC(t -> pGC) = t -> gc; + + free(t); +} + +static void nxagentAddGCToList(GCPtr pGC) +{ + struct nxagentGCRec *tempGC = malloc(sizeof(struct nxagentGCRec)); + + if (tempGC == NULL) + { + FatalError("nxagentAddGCToList: malloc failed."); + } + + #ifdef TEST + fprintf(stderr, "nxagentAddGCToList: Adding GC %p to list at memory %p list size is %d.\n", + (void *) pGC, (void *) tempGC, nxagentGCList.size); + #endif + + tempGC -> pGC = pGC; + tempGC -> gc = nxagentGC(pGC); + tempGC -> next = NULL; + + if (nxagentGCList.size == 0 || nxagentGCList.first == NULL || nxagentGCList.last == NULL) + { + nxagentGCList.first = tempGC; + } + else + { + nxagentGCList.last -> next = tempGC; + } + + nxagentGCList.last = tempGC; + nxagentGCList.size++; +} + +void nxagentFreeGCList() +{ + struct nxagentGCRec *tempGC; + + #ifdef TEST + fprintf(stderr, "nxagentFreeGCList: List size is %d first elt at %p last elt at %p.\n", + nxagentGCList.size, (void*)nxagentGCList.first, (void*)nxagentGCList.last); + #endif + + while ((tempGC = nxagentGetFirstGC())) + { + nxagentFreeGCRec(tempGC); + } +} + +static void nxagentRestoreGCList() +{ + struct nxagentGCRec *tempGC; + + #ifdef TEST + fprintf(stderr, "nxagentRestoreGCList: List size is %d first elt at %p last elt at %p.\n", + nxagentGCList.size, (void*)nxagentGCList.first, (void*)nxagentGCList.last); + #endif + + while ((tempGC = nxagentGetFirstGC())) + { + nxagentRestoreGCRec(tempGC); + } +} + +int nxagentDestroyNewGCResourceType(void * p, XID id) +{ + /* + * Address of the destructor is set in Init.c. + */ + + #ifdef TEST + fprintf(stderr, "nxagentDestroyNewGCResourceType: Destroying mirror id [%ld] for GC at [%p].\n", + nxagentGCPriv((GCPtr) p) -> mid, (void *) p); + #endif + + nxagentGCPriv((GCPtr) p) -> mid = None; + + return 1; +} + +static void nxagentReconnectGC(void *param0, XID param1, void * param2) +{ + XGCValues values; + unsigned long valuemask; + GCPtr pGC = (GCPtr) param0; + Bool *pBool = (Bool*)param2; + + if (pGC == NULL || !*pBool) + { + return; + } + + if (nxagentGC(pGC)) + { + nxagentAddGCToList(pGC); + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentReconnectGC: GCRec %p doesn't have a valid pointer to GC data.\n", (void*)pGC); + #endif + } + + #ifdef DEBUG + fprintf(stderr, "nxagentReconnectGC: GC at [%p].\n", (void *) pGC); + #endif + + valuemask = 0; + memset(&values,0,sizeof(XGCValues)); + values.function = pGC->alu; + valuemask |= GCFunction; + values.plane_mask = pGC->planemask; + valuemask |= GCPlaneMask; + values.foreground = nxagentPixel(pGC->fgPixel); + valuemask |= GCForeground; + values.background = nxagentPixel(pGC->bgPixel); + valuemask |= GCBackground; + + values.line_width = pGC->lineWidth; + valuemask |= GCLineWidth; + values.line_style = pGC->lineStyle; + valuemask |= GCLineStyle; + values.cap_style = pGC->capStyle; + valuemask |= GCCapStyle; + values.join_style = pGC->joinStyle; + valuemask |= GCJoinStyle; + values.fill_style = pGC->fillStyle; + valuemask |= GCFillStyle; + values.fill_rule = pGC->fillRule; + valuemask |= GCFillRule; + + if (!pGC -> tileIsPixel && (pGC -> tile.pixmap != NULL)) + { + if (nxagentPixmapIsVirtual(pGC -> tile.pixmap)) + { + values.tile = nxagentPixmap(nxagentRealPixmap(pGC -> tile.pixmap)); + } + else + { + values.tile = nxagentPixmap(pGC -> tile.pixmap); + } + + valuemask |= GCTile; + } + + if (pGC->stipple != NULL) + { + if (nxagentPixmapIsVirtual(pGC -> stipple)) + { + #ifdef TEST + fprintf(stderr, "nxagentReconnectGC: Reconnecting virtual stipple [%p] for GC [%p].\n", + (void *) pGC -> stipple, (void *) pGC); + #endif + + if (nxagentPixmap(nxagentRealPixmap(pGC -> stipple)) == 0) + { + nxagentReconnectPixmap(nxagentRealPixmap(pGC -> stipple), 0, pBool); + } + + values.stipple = nxagentPixmap(nxagentRealPixmap(pGC -> stipple)); + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentReconnectGC: Reconnecting stipple [%p] for GC [%p].\n", + (void *) pGC -> stipple, (void *) pGC); + #endif + + if (nxagentPixmap(pGC -> stipple) == 0) + { + nxagentReconnectPixmap(pGC -> stipple, 0, pBool); + } + + values.stipple = nxagentPixmap(pGC->stipple); + } + valuemask |= GCStipple; + } + + values.ts_x_origin = pGC->patOrg.x; + valuemask |= GCTileStipXOrigin; + values.ts_y_origin = pGC->patOrg.y; + valuemask |= GCTileStipYOrigin; + + if (pGC->font != NULL) + { + values.font = nxagentFont(pGC->font); + valuemask |= GCFont; + } + + values.subwindow_mode = pGC->subWindowMode; + valuemask |= GCSubwindowMode; + values.graphics_exposures = pGC->graphicsExposures; + valuemask |= GCGraphicsExposures; + values.clip_x_origin = pGC->clipOrg.x; + valuemask |= GCClipXOrigin; + values.clip_y_origin = pGC->clipOrg.y; + valuemask |= GCClipYOrigin; + valuemask |= GCClipMask; + values.dash_offset = pGC->dashOffset; + valuemask |= GCDashOffset; + + if (pGC->dash != NULL) + { + values.dashes = *pGC->dash; + valuemask |= GCDashList; + } + + values.arc_mode = pGC->arcMode; + valuemask |= GCArcMode; + + if ((nxagentGC(pGC) = XCreateGC(nxagentDisplay, + nxagentDefaultDrawables[pGC->depth], + valuemask, &values)) == NULL) + { + *pBool = False; + } + + nxagentReconnectClip(pGC, + pGC -> clientClipType, + pGC -> clientClip, nxagentGCPriv(pGC) -> nClipRects); + + #ifdef DEBUG + XSync(nxagentDisplay, 0); + #endif +} + +Bool nxagentReconnectAllGCs(void *p0) +{ + int cid; + Bool GCSuccess = True; + + #ifdef DEBUG + fprintf(stderr, "nxagentReconnectAllGCs\n"); + #endif + + /* + * The resource type RT_NX_GC is created on the + * server client only, so we can avoid to loop + * through all the clients. + */ + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_GC, nxagentReconnectGC, &GCSuccess); + + for (cid = 0; (cid < MAXCLIENTS) && GCSuccess; cid++) + { + if (clients[cid]) + { + #ifdef TEST + fprintf(stderr, "nxagentReconnectAllGCs: Going to reconnect GC of client [%d].\n", cid); + #endif + + FindClientResourcesByType(clients[cid], RT_GC, nxagentReconnectGC, &GCSuccess); + } + } + + #ifdef TEST + fprintf(stderr, "nxagentReconnectAllGCs: GCs reconnection completed.\n"); + #endif + + return GCSuccess; +} + +void nxagentDisconnectGC(void * p0, XID x1, void * p2) +{ + GCPtr pGC = (GCPtr) p0; + Bool* pBool = (Bool*) p2; + + if (!*pBool || !pGC) + { + if (!pGC) + { + #ifdef WARNING + fprintf(stderr, "nxagentDisconnectGC: WARNING! pGC is NULL.\n"); + #endif + } + + return; + } + + if (pGC -> stipple) + { + PixmapPtr pMap = pGC -> stipple; + + nxagentDisconnectPixmap(nxagentRealPixmap(pMap), 0, pBool); + } +} + +Bool nxagentDisconnectAllGCs() +{ + int cid; + Bool success = True; + + #ifdef DEBUG + fprintf(stderr, "nxagentDisconnectAllGCs\n"); + #endif + + /* + * The resource type RT_NX_GC is created on the + * server client only, so we can avoid to loop + * through all the clients. + */ + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_GC, + (FindResType) nxagentDisconnectGC, &success); + + for (cid = 0; (cid < MAXCLIENTS) && success; cid++) + { + if (clients[cid]) + { + #ifdef TEST + fprintf(stderr, "nxagentDisconnectAllGCs: Going to disconnect GC of client [%d].\n", cid); + #endif + + FindClientResourcesByType(clients[cid], RT_GC, + (FindResType) nxagentDisconnectGC, &success); + } + } + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectAllGCs: GCs disconnection completed.\n"); + #endif + + nxagentRestoreGCList(); + + nxagentDisconnectGraphicContexts(); + + return success; +} + +static void nxagentReconnectClip(GCPtr pGC, int type, void * pValue, int nRects) +{ + int i, size; + BoxPtr pBox; + XRectangle *pRects; + + #ifdef TEST + fprintf(stderr, "nxagentReconnectClip: going to change clip on GC [%p]\n", + (void *) pGC); + #endif + + #ifdef DEBUG + fprintf(stderr, "nxagentReconnectClip: Type is [%s].\n", (type == CT_NONE) ? + "CT_NONE" : (type == CT_REGION) ? "CT_REGION" : (type == CT_PIXMAP) ? + "CT_REGION" : "UNKNOWN"); + #endif + + switch(type) + { + case CT_NONE: + XSetClipMask(nxagentDisplay, nxagentGC(pGC), None); + break; + + case CT_REGION: + if (nxagentGCPriv(pGC)->pPixmap == NULL) + { + nRects = RegionNumRects((RegionPtr)pValue); + size = nRects * sizeof(*pRects); + pRects = (XRectangle *) malloc(size); + pBox = RegionRects((RegionPtr)pValue); + for (i = nRects; i-- > 0;) { + pRects[i].x = pBox[i].x1; + pRects[i].y = pBox[i].y1; + pRects[i].width = pBox[i].x2 - pBox[i].x1; + pRects[i].height = pBox[i].y2 - pBox[i].y1; + } + + /* + * Originally, the clip origin area were 0,0 + * but it didn't work with kedit and family, + * because it got the clip mask of the pixmap + * all traslated. + */ + + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), pGC -> clipOrg.x, pGC -> clipOrg.y, + pRects, nRects, Unsorted); + free((char *) pRects); + } + else + { + XSetClipMask(nxagentDisplay, nxagentGC(pGC), + nxagentPixmap(nxagentGCPriv(pGC)->pPixmap)); + + XSetClipOrigin(nxagentDisplay, nxagentGC(pGC), pGC -> clipOrg.x, pGC -> clipOrg.y); + } + + break; + + case CT_PIXMAP: + + XSetClipMask(nxagentDisplay, nxagentGC(pGC), + nxagentPixmap((PixmapPtr)pValue)); + + XSetClipOrigin(nxagentDisplay, nxagentGC(pGC), pGC -> clipOrg.x, pGC -> clipOrg.y); + + pGC->clientClip = (void *) (*pGC->pScreen->BitmapToRegion)((PixmapPtr) pValue); + + nxagentGCPriv(pGC)->pPixmap = (PixmapPtr)pValue; + + pValue = pGC->clientClip; + + type = CT_REGION; + + break; + + case CT_UNSORTED: + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, Unsorted); + break; + + case CT_YSORTED: + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, YSorted); + break; + + case CT_YXSORTED: + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, YXSorted); + break; + + case CT_YXBANDED: + XSetClipRectangles(nxagentDisplay, nxagentGC(pGC), + pGC->clipOrg.x, pGC->clipOrg.y, + (XRectangle *)pValue, nRects, YXBanded); + break; + } + + switch(type) + { + default: + break; + + case CT_UNSORTED: + case CT_YSORTED: + case CT_YXSORTED: + case CT_YXBANDED: + + /* + * other parts of server can only deal with CT_NONE, + * CT_PIXMAP and CT_REGION client clips. + */ + + pGC->clientClip = (void *) RegionFromRects(nRects, + (xRectangle *)pValue, type); + free(pValue); + pValue = pGC->clientClip; + type = CT_REGION; + + break; + } + + pGC->clientClipType = type; + pGC->clientClip = pValue; + + nxagentGCPriv(pGC)->nClipRects = nRects; +} + +static int nxagentCompareRegions(RegionPtr r1, RegionPtr r2) +{ + int i; + + /* + * It returns 1 if regions are equal, 0 otherwise + */ + + if (r1 == NULL && r2 == NULL) + { + return 1; + } + + if ((r1 == NULL) || (r2 == NULL)) + { + return 0; + } + + if (RegionNumRects(r1) != RegionNumRects(r2)) + { + return 0; + } + else if (RegionNumRects(r1) == 0) + { + return 1; + } + else if ((*RegionExtents(r1)).x1 != (*RegionExtents(r2)).x1) return 0; + else if ((*RegionExtents(r1)).x2 != (*RegionExtents(r2)).x2) return 0; + else if ((*RegionExtents(r1)).y1 != (*RegionExtents(r2)).y1) return 0; + else if ((*RegionExtents(r1)).y2 != (*RegionExtents(r2)).y2) return 0; + else + { + for (i = 0; i < RegionNumRects(r1); i++) + { + if (RegionRects(r1)[i].x1 != RegionRects(r2)[i].x1) return 0; + else if (RegionRects(r1)[i].x2 != RegionRects(r2)[i].x2) return 0; + else if (RegionRects(r1)[i].y1 != RegionRects(r2)[i].y1) return 0; + else if (RegionRects(r1)[i].y2 != RegionRects(r2)[i].y2) return 0; + } + } + + return 1; +} + +/* + * This function have to be called in the place + * of GetScratchGC if the GC will be used to per- + * form operations also on the remote X Server. + * This is why we call the XChangeGC at the end of + * the function. + */ +GCPtr nxagentGetScratchGC(unsigned depth, ScreenPtr pScreen) +{ + GCPtr pGC; + XGCValues values; + unsigned long mask; + int nxagentSaveGCTrap; + + /* + * The GC trap is temporarily disabled in + * order to allow the remote clipmask reset + * requested by GetScratchGC(). + */ + + nxagentSaveGCTrap = nxagentGCTrap; + + nxagentGCTrap = 0; + + pGC = GetScratchGC(depth, pScreen); + + nxagentGCTrap = nxagentSaveGCTrap; + + if (pGC == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentGetScratchGC: Failed to retrieve the scratch GC.\n"); + #endif + + return NULL; + } + + mask = 0; + + values.function = pGC -> alu; + mask |= GCFunction; + + values.plane_mask = pGC -> planemask; + mask |= GCPlaneMask; + + values.foreground = nxagentPixel(pGC -> fgPixel); + mask |= GCForeground; + + values.background = nxagentPixel(pGC -> bgPixel); + mask |= GCBackground; + + values.line_width = pGC -> lineWidth; + mask |= GCLineWidth; + + values.line_style = pGC -> lineStyle; + mask |= GCLineStyle; + + values.cap_style = pGC -> capStyle; + mask |= GCCapStyle; + + values.join_style = pGC -> joinStyle; + mask |= GCJoinStyle; + + values.fill_style = pGC -> fillStyle; + mask |= GCFillStyle; + + values.fill_rule = pGC -> fillRule; + mask |= GCFillRule; + + values.arc_mode = pGC -> arcMode; + mask |= GCArcMode; + + values.ts_x_origin = pGC -> patOrg.x; + mask |= GCTileStipXOrigin; + + values.ts_y_origin = pGC -> patOrg.y; + mask |= GCTileStipYOrigin; + + values.subwindow_mode = pGC -> subWindowMode; + mask |= GCSubwindowMode; + + values.graphics_exposures = pGC -> graphicsExposures; + mask |= GCGraphicsExposures; + + /* + * The GCClipMask is set to none inside + * the GetScratchGC() function. + */ + + values.clip_x_origin = pGC -> clipOrg.x; + mask |= GCClipXOrigin; + + values.clip_y_origin = pGC -> clipOrg.y; + mask |= GCClipYOrigin; + + XChangeGC(nxagentDisplay, nxagentGC(pGC), mask, &values); + + memset(&(nxagentGCPriv(pGC) -> lastServerValues), 0, sizeof(XGCValues)); + + return pGC; +} + +/* + * This function is only a wrapper for + * FreeScratchGC. + */ +void nxagentFreeScratchGC(GCPtr pGC) +{ + if (pGC == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentFreeScratchGC: WARNING! pGC is NULL.\n"); + #endif + + return; + } + + FreeScratchGC(pGC); +} + +/* + * The GCs belonging to this list are used + * only in the synchronization put images, + * to be sure they preserve the default va- + * lues and to avoid XChangeGC() requests. + */ + +GCPtr nxagentGetGraphicContext(DrawablePtr pDrawable) +{ + int i; + int result; + + for (i = 0; i < nxagentGraphicContextsSize; i++) + { + if (pDrawable -> depth == nxagentGraphicContexts[i].depth) + { + #ifdef DEBUG + fprintf(stderr, "nxagentGetGraphicContext: Found a valid GC at [%p] for depth [%d].\n", + (void *) nxagentGraphicContexts[i].pGC, pDrawable -> depth); + #endif + + /* + * Reconnect the GC if needed. + */ + + if (nxagentGraphicContexts[i].dirty == 1) + { + #ifdef DEBUG + fprintf(stderr, "nxagentGetGraphicContext: Going to reconnect the GC.\n"); + #endif + + result = 1; + + nxagentReconnectGC(nxagentGraphicContexts[i].pGC, (XID) 0, &result); + + if (result == 0) + { + #ifdef WARNING + fprintf(stderr, "nxagentGetGraphicContext: WARNING! Failed to reconnect the GC.\n"); + #endif + + return NULL; + } + + nxagentGraphicContexts[i].dirty = 0; + } + + return nxagentGraphicContexts[i].pGC; + } + } + + return nxagentCreateGraphicContext(pDrawable -> depth); +} + +GCPtr nxagentCreateGraphicContext(int depth) +{ + GCPtr pGC; + + nxagentGraphicContextsPtr nxagentGCs; + + XID attributes[2]; + + /* + * We have not found a GC, so we have + * to spread the list and add a new GC. + */ + + nxagentGCs = realloc(nxagentGraphicContexts, (nxagentGraphicContextsSize + 1) * sizeof(nxagentGraphicContextsRec)); + + if (nxagentGCs == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentCreateGraphicContext: Cannot allocate memory for a GC.\n"); + #endif + + return NULL; + } + + nxagentGraphicContexts = nxagentGCs; + + pGC = CreateScratchGC(nxagentDefaultScreen, depth); + + if (pGC == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentCreateGraphicContext: Failed to create a GC for depth [%d].\n", + depth); + #endif + + return NULL; + } + + /* + * Color used in nxagentFillRemoteRegion(). + */ + + attributes[0] = 0xc1c1c1; + + if (depth == 15 || depth == 16) + { + Color32to16(attributes[0]); + } + + /* + * The IncludeInferiors property is useful to + * solve problems when synchronizing windows + * covered by an invisible child. + */ + + attributes[1] = IncludeInferiors; + + ChangeGC(pGC, GCForeground | GCSubwindowMode, attributes); + + nxagentGraphicContexts[nxagentGraphicContextsSize].pGC = pGC; + nxagentGraphicContexts[nxagentGraphicContextsSize].depth = depth; + nxagentGraphicContexts[nxagentGraphicContextsSize].dirty = 0; + + nxagentGraphicContextsSize++; + + #ifdef DEBUG + fprintf(stderr, "nxagentCreateGraphicContext: GC [%p] for depth [%d] added to the list of size [%d].\n", + (void *) pGC, depth, nxagentGraphicContextsSize); + #endif + + return pGC; +} + +/* + * This initialization is called in the InitOutput() + * function immediately after opening the screen, + * which is used to create the GCs. + */ + +void nxagentAllocateGraphicContexts(void) +{ + int *depths; + + int i; + + depths = nxagentDepths; + + for (i = 0; i < nxagentNumDepths; i++) + { + nxagentCreateGraphicContext(*depths); + + depths++; + } +} + +void nxagentDisconnectGraphicContexts(void) +{ + int i; + + for (i = 0; i < nxagentGraphicContextsSize; i++) + { + nxagentGraphicContexts[i].dirty = 1; + } + + return; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/GCOps.c b/nx-X11/programs/Xserver/hw/nxagent/GCOps.c new file mode 100644 index 000000000..1bca067fc --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/GCOps.c @@ -0,0 +1,2104 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include "scrnintstr.h" +#include "resource.h" +#include "dixstruct.h" +#include "../../fb/fb.h" + +#include "Agent.h" +#include "Composite.h" +#include "Display.h" +#include "Visual.h" +#include "Drawable.h" +#include "Pixmaps.h" +#include "GCs.h" +#include "Image.h" +#include "Font.h" +#include "Events.h" +#include "Client.h" +#include "Trap.h" +#include "Holder.h" +#include "Args.h" +#include "Screen.h" + +#include "compext/Compext.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +/* + * Temporarily set/reset the trap. + */ + +static int nxagentSaveGCTrap; + +#define SET_GC_TRAP() \ +{ \ + nxagentSaveGCTrap = nxagentGCTrap;\ +\ + nxagentGCTrap = 1; \ +} + +#define RESET_GC_TRAP() \ +{ \ + nxagentGCTrap = nxagentSaveGCTrap; \ +} + +/* + * This is currently unused. + */ + +RegionPtr nxagentBitBlitHelper(GC *pGC); + +/* + * The NX agent implementation of the + * X server's graphics functions. + */ + +void nxagentFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nSpans, + xPoint *pPoints, int *pWidths, int fSorted) +{ + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to FillSpans on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + fbFillSpans(nxagentVirtualDrawable(pDrawable), pGC, nSpans, pPoints, pWidths, fSorted); + } + else + { + fbFillSpans(pDrawable, pGC, nSpans, pPoints, pWidths, fSorted); + } +} + +void nxagentSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *pSrc, + xPoint *pPoints, int *pWidths, int nSpans, int fSorted) +{ + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to SetSpans on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + fbSetSpans(nxagentVirtualDrawable(pDrawable), pGC, pSrc, pPoints, pWidths, nSpans, fSorted); + } + else + { + fbSetSpans(pDrawable, pGC, pSrc, pPoints, pWidths, nSpans, fSorted); + } +} + +void nxagentGetSpans(DrawablePtr pDrawable, int maxWidth, xPoint *pPoints, + int *pWidths, int nSpans, char *pBuffer) +{ + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: going to GetSpans on FB pixmap [%p].\n", + (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + fbGetSpans(nxagentVirtualDrawable(pDrawable), maxWidth, pPoints, pWidths, nSpans, pBuffer); + } + else + { + fbGetSpans(pDrawable, maxWidth, pPoints, pWidths, nSpans, pBuffer); + } +} + +void nxagentQueryBestSize(int class, unsigned short *pwidth, + unsigned short *pheight, ScreenPtr pScreen) +{ + unsigned width, test; + + switch(class) + { + case CursorShape: + if (*pwidth > pScreen->width) + *pwidth = pScreen->width; + if (*pheight > pScreen->height) + *pheight = pScreen->height; + break; + case TileShape: + case StippleShape: + width = *pwidth; + if (!width) break; + /* Return the closes power of two not less than what they gave me */ + test = 0x80000000; + /* Find the highest 1 bit in the width given */ + while(!(test & width)) + test >>= 1; + /* If their number is greater than that, bump up to the next + * power of two */ + if((test - 1) & width) + test <<= 1; + *pwidth = test; + /* We don't care what height they use */ + break; + } +} + +RegionPtr nxagentBitBlitHelper(GC *pGC) +{ + #ifdef TEST + fprintf(stderr, "nxagentBitBlitHelper: Called for GC at [%p].\n", (void *) pGC); + #endif + + /* + * Force NullRegion. We consider enough the graphics + * expose events generated internally by the nxagent + * server. + */ + + #ifdef TEST + fprintf(stderr, "nxagentBitBlitHelper: WARNING! Skipping check on exposures events.\n"); + #endif + + return NullRegion; +} + +/* + * The deferring of X_RenderCompositeTrapezoids caused + * an ugly effect on pulldown menu: as the background + * may be not synchronized, the text floats in an invi- + * sible window. To avoid such effects, we use a system + * to guess if the destination target of a copy area + * is a popup, by assuming that those kind of windows + * use the override redirect property. + */ + +int nxagentWindowIsPopup(DrawablePtr pDrawable) +{ + WindowPtr parent; + + int windowIsPopup; + int level; + + if (pDrawable -> type != DRAWABLE_WINDOW) + { + return 0; + } + + windowIsPopup = 0; + + if (((WindowPtr) pDrawable) -> overrideRedirect == 1) + { + windowIsPopup = 1; + } + else + { + parent = ((WindowPtr) pDrawable) -> parent; + + /* + * Go up on the tree until a parent + * exists or 4 windows has been che- + * cked. This seems a good limit to + * up children's popup. + */ + + level = 0; + + while (parent != NULL && ++level <= 4) + { + #ifdef DEBUG + fprintf(stderr, "nxagentWindowIsPopup: Window [%p] has parent [%p] in tree with OverrideRedirect [%d] " + " Level [%d].\n", (void *) pDrawable, (void *) parent, parent -> overrideRedirect, level); + #endif + + if (parent -> overrideRedirect == 1) + { + windowIsPopup = 1; + + break; + } + + parent = parent -> parent; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentWindowIsPopup: Window [%p] %s to be a popup.\n", (void *) pDrawable, + windowIsPopup == 1 ? "seems" : "does not seem"); + #endif + + return windowIsPopup; +} + +/* + * This function returns 1 if the + * XCopyArea request must be skipped. + */ + +int nxagentDeferCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, int srcx, int srcy, int width, + int height, int dstx, int dsty) +{ + RegionPtr pSrcRegion; + RegionPtr pClipRegion, pCorruptedRegion; + RegionRec corruptedRegion, tmpRegion; + + /* + * If the destination drawable is a popup + * window, we try to synchronize the source + * drawable to show a nice menu. Anyway if + * this synchronization breaks, the copy area + * is handled in the normal way. + */ + +/* +FIXME: The popup could be synchronized with one + single put image, clipped to the corrup- + ted region. As an intermediate step, the + pixmap to synchronize could be copied on + a cleared scratch pixmap, in order to + have a solid color in the clipped regions. +*/ + + if (nxagentOption(DeferLevel) >= 2 && + pSrcDrawable -> type == DRAWABLE_PIXMAP && + nxagentPixmapContainTrapezoids((PixmapPtr) pSrcDrawable) == 1 && + nxagentWindowIsPopup(pDstDrawable) == 1) + { + pSrcRegion = nxagentCreateRegion(pSrcDrawable, NULL, srcx, srcy, width, height); + + #ifdef DEBUG + fprintf(stderr, "nxagentDeferCopyArea: Copying to a popup menu. Source region [%d,%d,%d,%d].\n", + pSrcRegion -> extents.x1, pSrcRegion -> extents.y1, + pSrcRegion -> extents.x2, pSrcRegion -> extents.y2); + #endif + + RegionInit(&corruptedRegion, NullBox, 1); + + RegionIntersect(&corruptedRegion, + pSrcRegion, nxagentCorruptedRegion(pSrcDrawable)); + + if (RegionNil(&corruptedRegion) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentDeferCopyArea: Forcing the synchronization of source drawable at [%p].\n", + (void *) pSrcDrawable); + #endif + + nxagentSynchronizeRegion(pSrcDrawable, &corruptedRegion, EVENT_BREAK, NULL); + } + + RegionUninit(&corruptedRegion); + + nxagentFreeRegion(pSrcDrawable, pSrcRegion); + + if (nxagentDrawableStatus(pSrcDrawable) == Synchronized) + { + return 0; + } + } + + /* + * We are going to decide if the source drawable + * must be synchronized before using it, or if + * the copy will be clipped to the synchronized + * source region. + */ + + if ((pDstDrawable -> type == DRAWABLE_PIXMAP && + nxagentOption(DeferLevel) > 0) || nxagentOption(DeferLevel) >= 3) + { + pClipRegion = nxagentCreateRegion(pSrcDrawable, NULL, srcx, srcy, + width, height); + + /* + * We called this variable pCorruptedRegion + * because in the worst case the corrupted + * region will be equal to the destination + * region. The GC's clip mask is used to + * narrow the destination. + */ + + pCorruptedRegion = nxagentCreateRegion(pDstDrawable, pGC, dstx, dsty, + width, height); + + #ifdef DEBUG + fprintf(stderr, "nxagentDeferCopyArea: Copy area source region is [%d,%d,%d,%d].\n", + pClipRegion -> extents.x1, pClipRegion -> extents.y1, + pClipRegion -> extents.x2, pClipRegion -> extents.y2); + #endif + + RegionSubtract(pClipRegion, pClipRegion, nxagentCorruptedRegion(pSrcDrawable)); + + #ifdef DEBUG + fprintf(stderr, "nxagentDeferCopyArea: Usable copy area source region is [%d,%d,%d,%d].\n", + pClipRegion -> extents.x1, pClipRegion -> extents.y1, + pClipRegion -> extents.x2, pClipRegion -> extents.y2); + #endif + + if (pGC -> clientClip == NULL || pGC -> clientClipType != CT_REGION) + { + #ifdef WARNING + + if (pGC -> clientClipType != CT_NONE) + { + fprintf(stderr, "nxagentDeferCopyArea: WARNING! pGC [%p] has a clip type [%d].\n", + (void *) pGC, pGC -> clientClipType); + } + + #endif + + RegionTranslate(pClipRegion, dstx - srcx, dsty - srcy); + } + else + { + RegionInit(&tmpRegion, NullBox, 1); + + #ifdef DEBUG + fprintf(stderr, "nxagentDeferCopyArea: Going to modify the original GC [%p] with clip mask " + "[%d,%d,%d,%d] and origin [%d,%d].\n", + (void *) pGC, + ((RegionPtr) pGC -> clientClip) -> extents.x1, ((RegionPtr) pGC -> clientClip) -> extents.y1, + ((RegionPtr) pGC -> clientClip) -> extents.x2, ((RegionPtr) pGC -> clientClip) -> extents.y2, + pGC -> clipOrg.x, pGC -> clipOrg.y); + #endif + + RegionCopy(&tmpRegion, (RegionPtr) pGC -> clientClip); + + if (pGC -> clipOrg.x != 0 || pGC -> clipOrg.y != 0) + { + RegionTranslate(&tmpRegion, pGC -> clipOrg.x, pGC -> clipOrg.y); + } + + RegionTranslate(pClipRegion, dstx - srcx, dsty - srcy); + + RegionIntersect(pClipRegion, &tmpRegion, pClipRegion); + + RegionUninit(&tmpRegion); + } + + /* + * The corrupted region on the destination + * drawable is composed by the areas of the + * destination that we are not going to copy. + */ + + RegionSubtract(pCorruptedRegion, pCorruptedRegion, pClipRegion); + + #ifdef DEBUG + fprintf(stderr, "nxagentDeferCopyArea: Recomputed clip region is [%d,%d,%d,%d][%ld].\n", + pClipRegion -> extents.x1, pClipRegion -> extents.y1, + pClipRegion -> extents.x2, pClipRegion -> extents.y2, + RegionNumRects(pClipRegion)); + + fprintf(stderr, "nxagentDeferCopyArea: Inherited corrupted region is [%d,%d,%d,%d][%ld].\n", + pCorruptedRegion -> extents.x1, pCorruptedRegion -> extents.y1, + pCorruptedRegion -> extents.x2, pCorruptedRegion -> extents.y2, + RegionNumRects(pCorruptedRegion)); + #endif + + /* + * The destination drawable inherits both the + * synchronized and the corrupted region. + */ + + if (RegionNil(pClipRegion) == 0) + { + nxagentUnmarkCorruptedRegion(pDstDrawable, pClipRegion); + } + + if (RegionNil(pCorruptedRegion) == 0) + { + nxagentMarkCorruptedRegion(pDstDrawable, pCorruptedRegion); + } + + if (RegionNil(pClipRegion) == 0) + { + GCPtr targetGC; + + CARD32 targetAttributes[2]; + + Bool pClipRegionFree = True; + + /* + * As we want to copy only the synchronized + * areas of the source drawable, we create + * a new GC copying the original one and + * setting a new clip mask. + */ + + targetGC = GetScratchGC(pDstDrawable -> depth, pDstDrawable -> pScreen); + + ValidateGC(pDstDrawable, targetGC); + + CopyGC(pGC, targetGC, GCFunction | GCPlaneMask | GCSubwindowMode | + GCClipXOrigin | GCClipYOrigin | GCClipMask | GCForeground | + GCBackground | GCGraphicsExposures); + + if (RegionNumRects(pClipRegion) == 1) + { + /* + * If the region to copy is formed by one + * rectangle, we change only the copy coor- + * dinates. + */ + + srcx = srcx + pClipRegion -> extents.x1 - dstx; + srcy = srcy + pClipRegion -> extents.y1 - dsty; + + dstx = pClipRegion -> extents.x1; + dsty = pClipRegion -> extents.y1; + + width = pClipRegion -> extents.x2 - pClipRegion -> extents.x1; + height = pClipRegion -> extents.y2 - pClipRegion -> extents.y1; + } + else + { + /* + * Setting the clip mask origin. This + * operation must precede the clip chan- + * ge, because the origin information is + * used in the XSetClipRectangles(). + */ + + targetAttributes[0] = 0; + targetAttributes[1] = 0; + + ChangeGC(targetGC, GCClipXOrigin | GCClipYOrigin, targetAttributes); + + /* + * Setting the new clip mask. + */ + + nxagentChangeClip(targetGC, CT_REGION, pClipRegion, 0); + + /* + * Next call to nxagentChangeClip() will destroy + * pClipRegion, so it has not to be freed. + */ + + pClipRegionFree = False; + + #ifdef DEBUG + fprintf(stderr, "nxagentDeferCopyArea: Going to execute a copy area with clip mask " + "[%d,%d,%d,%d] and origin [%d,%d].\n", ((RegionPtr) targetGC -> clientClip) -> extents.x1, + ((RegionPtr) targetGC -> clientClip) -> extents.y1, + ((RegionPtr) targetGC -> clientClip) -> extents.x2, + ((RegionPtr) targetGC -> clientClip) -> extents.y2, + targetGC -> clipOrg.x, targetGC -> clipOrg.y); + #endif + } + + XCopyArea(nxagentDisplay, nxagentDrawable(pSrcDrawable), nxagentDrawable(pDstDrawable), + nxagentGC(targetGC), srcx, srcy, width, height, dstx, dsty); + + nxagentChangeClip(targetGC, CT_NONE, NullRegion, 0); + + if (pClipRegionFree == True) + { + nxagentFreeRegion(pSrcDrawable, pClipRegion); + } + + FreeScratchGC(targetGC); + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentDeferCopyArea: The clipped region is NIL. CopyArea skipped.\n"); + #endif + + /* + * The pClipRegion is destroyed calling nxagentChangeClip(), + * so we deallocate it explicitly only if we don't change + * the clip. + */ + + nxagentFreeRegion(pSrcDrawable, pClipRegion); + } + + nxagentFreeRegion(pSrcDrawable, pCorruptedRegion); + + return 1; + } + else + { + pSrcRegion = nxagentCreateRegion(pSrcDrawable, NULL, srcx, srcy, width, height); + + #ifdef DEBUG + fprintf(stderr, "nxagentDeferCopyArea: Source region [%d,%d,%d,%d].\n", + pSrcRegion -> extents.x1, pSrcRegion -> extents.y1, + pSrcRegion -> extents.x2, pSrcRegion -> extents.y2); + #endif + + RegionInit(&corruptedRegion, NullBox, 1); + + RegionIntersect(&corruptedRegion, + pSrcRegion, nxagentCorruptedRegion(pSrcDrawable)); + + if (RegionNil(&corruptedRegion) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentDeferCopyArea: Forcing the synchronization of source drawable at [%p].\n", + (void *) pSrcDrawable); + #endif + + nxagentSynchronizeRegion(pSrcDrawable, &corruptedRegion /*pSrcRegion*/, NEVER_BREAK, NULL); + } + + RegionUninit(&corruptedRegion); + + nxagentFreeRegion(pSrcDrawable, pSrcRegion); + } + + return 0; +} + +RegionPtr nxagentCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, int srcx, int srcy, int width, + int height, int dstx, int dsty) +{ + int leftPad = 0; + unsigned int format; + unsigned long planeMask = 0xffffffff; + + RegionPtr pDstRegion; + + int skip = 0; + + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Image src [%s:%p], dst [%s:%p] (%d,%d) -> (%d,%d) size (%d,%d)\n", + (pSrcDrawable -> type == DRAWABLE_PIXMAP) ? "PIXMAP" : "WINDOW", (void *) pSrcDrawable, + (pDstDrawable -> type == DRAWABLE_PIXMAP) ? "PIXMAP" : "WINDOW", + (void *) pDstDrawable, srcx, srcy, dstx, dsty, width, height); + #endif + + /* + * Here, before using fbDoCopy() called by fbCopyArea(), + * it should be provided that the cast in fbDoCopy() from + * int to short int would not cut off significative bits. + */ + + if (dstx + pDstDrawable->x + width > 32767) + { + #ifdef WARNING + fprintf(stderr, "nxagentCopyArea: x2 exceeding short int.\n"); + #endif + + width = 32767 - dstx - pDstDrawable->x; + + if (width <= 0) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Returning null on x2 check.\n"); + #endif + + return NullRegion; + } + } + + if (dstx + pDstDrawable->x < -32768) + { + #ifdef WARNING + fprintf(stderr, "nxagentCopyArea: x1 exceeding short int.\n"); + #endif + + width += pDstDrawable->x + dstx + 32768; + srcx -= pDstDrawable->x + dstx + 32768; + dstx = -32768 - pDstDrawable->x; + + if (width <= 0) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Returning null on x1 check.\n"); + #endif + + return NullRegion; + } + } + + if (dsty + pDstDrawable->y + height > 32767) + { + #ifdef WARNING + fprintf(stderr, "nxagentCopyArea: y2 exceeding short int.\n"); + #endif + + height = 32767 - dsty - pDstDrawable->y; + + if (height <= 0) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Returning null on y2 check.\n"); + #endif + + return NullRegion; + } + } + + if (dsty + pDstDrawable->y < -32768) + { + #ifdef WARNING + fprintf(stderr, "nxagentCopyArea: y1 exceeding short int.\n"); + #endif + + height += 32768 + pDstDrawable->y + dsty; + srcy -= 32768 + pDstDrawable->y + dsty; + dsty = -32768 - pDstDrawable->y; + + if (height <= 0) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Returning null on y1 check.\n"); + #endif + + return NullRegion; + } + } + + + if (nxagentGCTrap == 1 || nxagentShmTrap == 1) + { + if (pSrcDrawable -> type == DRAWABLE_PIXMAP && + pDstDrawable -> type == DRAWABLE_PIXMAP) + { + return fbCopyArea(nxagentVirtualDrawable(pSrcDrawable), + nxagentVirtualDrawable(pDstDrawable), + pGC, srcx, srcy, width, height, dstx, dsty); + } + else if (pSrcDrawable -> type == DRAWABLE_PIXMAP) + { + return fbCopyArea(nxagentVirtualDrawable(pSrcDrawable), pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty); + } + else if (pDstDrawable -> type == DRAWABLE_PIXMAP) + { + return fbCopyArea(pSrcDrawable, nxagentVirtualDrawable(pDstDrawable), + pGC, srcx, srcy, width, height, dstx, dsty); + } + else + { + return fbCopyArea(pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty); + } + + return NullRegion; + } + + /* + * Try to detect if the copy area is to a window + * that is unmapped or fully covered. Similarly + * to the check in Image.c, this is of little use. + */ + + if (nxagentOption(IgnoreVisibility) == 0 && pDstDrawable -> type == DRAWABLE_WINDOW && + (nxagentWindowIsVisible((WindowPtr) pDstDrawable) == 0 || + (nxagentDefaultWindowIsVisible() == 0 && nxagentCompositeEnable == 0))) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Prevented operation on fully obscured window at [%p].\n", + (void *) pDstDrawable); + #endif + + return NullRegion; + } + + /* + * If the pixmap is on shared memory, we can't + * know if the pixmap content is changed and + * so have to translate the operation in a put + * image operation. This can seriously affect + * the performance. + */ + + if (pSrcDrawable -> type == DRAWABLE_PIXMAP && + nxagentIsShmPixmap((PixmapPtr) pSrcDrawable)) + { + char *data; + int depth, length; + + depth = pSrcDrawable -> depth; + + format = (depth == 1) ? XYPixmap : ZPixmap; + + length = nxagentImageLength(width, height, format, leftPad, depth); + + if ((data = malloc(length)) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentCopyArea: WARNING! Failed to allocate memory for the operation.\n"); + #endif + + return NullRegion; + } + + fbGetImage(nxagentVirtualDrawable(pSrcDrawable), srcx, srcy, width, height, format, planeMask, data); + + /* + * If the source is a shared memory pixmap, + * put the image directly to the destination. + */ + + nxagentPutImage(pDstDrawable, pGC, depth, dstx, dsty, + width, height, leftPad, format, data); + + #ifdef TEST + fprintf(stderr,"nxagentCopyArea: Realize Pixmap %p virtual %p x %d y %d w %d h %d\n", + (void *) pSrcDrawable, (void *) nxagentVirtualDrawable(pSrcDrawable), + srcx, srcy, width, height); + #endif + + free(data); + + /* + * If the source is a shared memory pixmap, the + * content of the framebuffer has been placed + * directly on the destination so we can skip + * the copy area operation. + */ + + skip = 1; + } + + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Image src [%s:%p], dst [%s:%p] sx %d sy %d dx %d dy %d size w %d h %d\n", + ((pSrcDrawable)->type == DRAWABLE_PIXMAP) ? "PIXMAP" : "WINDOW", (void *) pSrcDrawable, + ((pDstDrawable)->type == DRAWABLE_PIXMAP) ? "PIXMAP" : "WINDOW", + (void *) pDstDrawable, srcx, srcy, dstx, dsty, width, height); + #endif + + if (skip == 0 && nxagentDrawableStatus(pSrcDrawable) == NotSynchronized) + { + skip = nxagentDeferCopyArea(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, + width, height, dstx, dsty); + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentCopyArea: Source drawable at [%p] already synchronized.\n", + (void *) pSrcDrawable); + } + #endif + + if (skip == 0) + { + XCopyArea(nxagentDisplay, nxagentDrawable(pSrcDrawable), nxagentDrawable(pDstDrawable), + nxagentGC(pGC), srcx, srcy, width, height, dstx, dsty); + + /* + * The copy area restored the synchroni- + * zation status of destination drawable. + */ + + if (nxagentDrawableStatus(pDstDrawable) == NotSynchronized) + { + pDstRegion = nxagentCreateRegion(pDstDrawable, pGC, dstx, dsty, width, height); + + nxagentUnmarkCorruptedRegion(pDstDrawable, pDstRegion); + + nxagentFreeRegion(pDstDrawable, pDstRegion); + } + } + + if (nxagentDrawableContainGlyphs(pSrcDrawable) == 1) + { + nxagentSetDrawableContainGlyphs(pDstDrawable, 1); + } + + if (pSrcDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentIncreasePixmapUsageCounter((PixmapPtr) pSrcDrawable); + } + + if (pSrcDrawable -> type == DRAWABLE_PIXMAP && + pDstDrawable -> type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Going to copy area from virtual pixmap [%p] to [%p]\n", + (void *) nxagentVirtualDrawable(pSrcDrawable), + (void *) nxagentVirtualDrawable(pDstDrawable)); + #endif + + return fbCopyArea(nxagentVirtualDrawable(pSrcDrawable), + nxagentVirtualDrawable(pDstDrawable), + pGC, srcx, srcy, width, height, dstx, dsty); + } + else if (pSrcDrawable -> type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Going to copy area from virtual pixmap [%p] to window [%p]\n", + (void *) nxagentVirtualDrawable(pSrcDrawable), + (void *) pDstDrawable); + #endif + + return fbCopyArea(nxagentVirtualDrawable(pSrcDrawable), pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty); + } + else if (pDstDrawable -> type == DRAWABLE_PIXMAP) + { + /* + * If we are here the source drawable + * must be a window. + */ + + if (((WindowPtr) pSrcDrawable) -> viewable) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Going to copy area from window [%p] to virtual pixmap [%p]\n", + (void *) pSrcDrawable, (void *) nxagentVirtualDrawable(pDstDrawable)); + #endif + + return fbCopyArea(pSrcDrawable, nxagentVirtualDrawable(pDstDrawable), + pGC, srcx, srcy, width, height, dstx, dsty); + } + } + else + { + /* + * If we are here the source drawable + * must be a window. + */ + + if (((WindowPtr) pSrcDrawable) -> viewable) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyArea: Going to copy area from window [%p] to window [%p]\n", + (void *) pSrcDrawable, (void *) pDstDrawable); + #endif + + return fbCopyArea(pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty); + } + } + + return miHandleExposures(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty, 0); +} + +RegionPtr nxagentCopyPlane(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, int srcx, int srcy, int width, int height, + int dstx, int dsty, unsigned long plane) +{ + unsigned int format; + int leftPad = 0; + unsigned long planeMask = 0xffffffff; + + RegionPtr pSrcRegion, pDstRegion; + RegionRec corruptedRegion; + + int skip = 0; + + #ifdef TEST + fprintf(stderr, "nxagentCopyPlane: Image src [%s:%p], dst [%s:%p] (%d,%d) -> (%d,%d) size (%d,%d)\n", + ((pSrcDrawable)->type == DRAWABLE_PIXMAP) ? "PIXMAP" : "WINDOW", (void *) pSrcDrawable, + ((pDstDrawable)->type == DRAWABLE_PIXMAP) ? "PIXMAP" : "WINDOW", + (void *) pDstDrawable, srcx, srcy, dstx, dsty, width, height); + #endif + + if (nxagentGCTrap == 1 || nxagentShmTrap == 1) + { + if (pSrcDrawable -> type == DRAWABLE_PIXMAP && + pDstDrawable -> type == DRAWABLE_PIXMAP) + { + return fbCopyPlane(nxagentVirtualDrawable(pSrcDrawable), + nxagentVirtualDrawable(pDstDrawable), + pGC, srcx, srcy, width, height, dstx, dsty, plane); + } + else if (pSrcDrawable -> type == DRAWABLE_PIXMAP) + { + return fbCopyPlane(nxagentVirtualDrawable(pSrcDrawable), pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty, plane); + } + else if (pDstDrawable -> type == DRAWABLE_PIXMAP) + { + return fbCopyPlane(pSrcDrawable, nxagentVirtualDrawable(pDstDrawable), + pGC, srcx, srcy, width, height, dstx, dsty, plane); + } + else + { + return fbCopyPlane(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, + dstx, dsty, plane); + } + + return NullRegion; + } + + /* + * If the pixmap is on shared memory, we can't + * know if the pixmap content is changed and + * so have to translate the operation in a put + * image operation. This can seriously affect + * the performance. + */ + + if (pSrcDrawable -> type == DRAWABLE_PIXMAP && + nxagentIsShmPixmap((PixmapPtr) pSrcDrawable)) + { + char *data; + int depth, length; + + depth = pSrcDrawable -> depth; + + format = (depth == 1) ? XYPixmap : ZPixmap; + + length = nxagentImageLength(width, height, format, leftPad, depth); + + if ((data = malloc(length)) == NULL) + { + #ifdef DEBUG + fprintf(stderr, "nxagentCopyPlane: WARNING! Failed to allocate memory for the operation.\n"); + #endif + + return 0; + } + + fbGetImage(nxagentVirtualDrawable(pSrcDrawable), srcx, srcy, width, height, format, planeMask, data); + + /* + * If the source is a shared memory pixmap, + * put the image directly to the destination. + */ + + nxagentPutImage(pDstDrawable, pGC, depth, dstx, dsty, + width, height, leftPad, format, data); + + #ifdef TEST + fprintf(stderr,"nxagentCopyPlane: Synchronize Pixmap %p virtual %p x %d y %d w %d h %d \n", + (void *) pSrcDrawable, (void *) nxagentVirtualDrawable(pSrcDrawable), + srcx, srcy, width, height); + #endif + + free(data); + + /* + * If the source is a shared memory pixmap, the + * content of the framebuffer has been placed + * directly on the destination so we can skip + * the copy plane operation. + */ + + skip = 1; + } + + if (skip == 0 && nxagentDrawableStatus(pSrcDrawable) == NotSynchronized) + { + if (pDstDrawable -> type == DRAWABLE_PIXMAP && + nxagentOption(DeferLevel) > 0) + { + pDstRegion = nxagentCreateRegion(pDstDrawable, pGC, dstx, dsty, width, height); + + nxagentMarkCorruptedRegion(pDstDrawable, pDstRegion); + + nxagentFreeRegion(pDstDrawable, pDstRegion); + + skip = 1; + } + else + { + pSrcRegion = nxagentCreateRegion(pSrcDrawable, NULL, srcx, srcy, width, height); + + RegionInit(&corruptedRegion, NullBox, 1); + + RegionIntersect(&corruptedRegion, + pSrcRegion, nxagentCorruptedRegion(pSrcDrawable)); + + if (RegionNil(&corruptedRegion) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyPlane: Forcing the synchronization of source drawable at [%p].\n", + (void *) pSrcDrawable); + #endif + + nxagentSynchronizeRegion(pSrcDrawable, &corruptedRegion /*pSrcRegion*/, NEVER_BREAK, NULL); + + pDstRegion = nxagentCreateRegion(pDstDrawable, pGC, dstx, dsty, width, height); + + nxagentUnmarkCorruptedRegion(pDstDrawable, pDstRegion); + + nxagentFreeRegion(pDstDrawable, pDstRegion); + } + + RegionUninit(&corruptedRegion); + + nxagentFreeRegion(pSrcDrawable, pSrcRegion); + } + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentCopyPlane: Source drawable at [%p] already synchronized.\n", + (void *) pSrcDrawable); + } + #endif + + if (skip == 0) + { + XCopyPlane(nxagentDisplay, + nxagentDrawable(pSrcDrawable), nxagentDrawable(pDstDrawable), + nxagentGC(pGC), srcx, srcy, width, height, dstx, dsty, plane); + } + + if ((pSrcDrawable)->type == DRAWABLE_PIXMAP && + (pDstDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "nxagentCopyPlane: going to copy plane from FB pixmap [%p] to [%p].\n", + (void *) nxagentVirtualDrawable(pSrcDrawable), + (void *) nxagentVirtualDrawable(pDstDrawable)); + #endif + + return fbCopyPlane(nxagentVirtualDrawable(pSrcDrawable), + nxagentVirtualDrawable(pDstDrawable), + pGC, srcx, srcy, width, height, dstx, dsty, plane); + } + else if (pSrcDrawable -> type == DRAWABLE_PIXMAP) + { + return fbCopyPlane(nxagentVirtualDrawable(pSrcDrawable), pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty, plane); + } + else if (pDstDrawable -> type == DRAWABLE_PIXMAP) + { + return fbCopyPlane(pSrcDrawable, nxagentVirtualDrawable(pDstDrawable), pGC, + srcx, srcy, width, height, dstx, dsty, plane); + } + else + { + return fbCopyPlane(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty, plane); + } + + return miHandleExposures(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty, plane); +} + +void nxagentPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, + int nPoints, xPoint *pPoints) +{ + #ifdef TEST + fprintf(stderr, "nxagentPolyPoint: Drawable at [%p] GC at [%p] Points [%d].\n", + (void *) pDrawable, (void *) pGC, nPoints); + #endif + + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + fbPolyPoint(nxagentVirtualDrawable(pDrawable), pGC, mode, nPoints, pPoints); + } + else + { + fbPolyPoint(pDrawable, pGC, mode, nPoints, pPoints); + } + + return; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to poly point on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly point enters with virtual pixmap [%p] parent is [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XDrawPoints(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), (XPoint *) pPoints, nPoints, mode); + } + } + else + { + XDrawPoints(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XPoint *) pPoints, nPoints, mode); + } + + fbPolyPoint(nxagentVirtualDrawable(pDrawable), pGC, mode, nPoints, pPoints); + + return; + } + else + { + XDrawPoints(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XPoint *) pPoints, nPoints, mode); + + fbPolyPoint(pDrawable, pGC, mode, nPoints, pPoints); + } +} + +void nxagentPolyLines(DrawablePtr pDrawable, GCPtr pGC, int mode, + int nPoints, xPoint *pPoints) +{ + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + fbPolyLine(nxagentVirtualDrawable(pDrawable), pGC, mode, nPoints, pPoints); + } + else + { + fbPolyLine(pDrawable, pGC, mode, nPoints, pPoints); + } + + return; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to poly line on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly lines enters with virtual pixmap = [%p] parent is = [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XDrawLines(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), (XPoint *) pPoints, nPoints, mode); + } + } + else + { + XDrawLines(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XPoint *) pPoints, nPoints, mode); + } + + fbPolyLine(nxagentVirtualDrawable(pDrawable), pGC, mode, nPoints, pPoints); + + return; + } + else + { + XDrawLines(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XPoint *) pPoints, nPoints, mode); + + fbPolyLine(pDrawable, pGC, mode, nPoints, pPoints); + } +} + +void nxagentPolySegment(DrawablePtr pDrawable, GCPtr pGC, + int nSegments, xSegment *pSegments) +{ + #ifdef TEST + + if (nSegments == 1) + { + fprintf(stderr, "nxagentPolySegment: Drawable at [%p] GC at [%p] Segment [%d,%d,%d,%d].\n", + (void *) pDrawable, (void *) pGC, + pSegments -> x1, pSegments -> y1, pSegments -> x2, pSegments -> y2); + } + else + { + fprintf(stderr, "nxagentPolySegment: Drawable at [%p] GC at [%p] Segments [%d].\n", + (void *) pDrawable, (void *) pGC, nSegments); + } + + #endif + + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + fbPolySegment(nxagentVirtualDrawable(pDrawable), pGC, nSegments, pSegments); + } + else + { + fbPolySegment(pDrawable, pGC, nSegments, pSegments); + } + + return; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to poly segment on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly segment enters with virtual pixmap = [%p] parent is = [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XDrawSegments(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), (XSegment *) pSegments, nSegments); + } + } + else + { + XDrawSegments(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XSegment *) pSegments, nSegments); + } + + SET_GC_TRAP(); + fbPolySegment(nxagentVirtualDrawable(pDrawable), pGC, nSegments, pSegments); + RESET_GC_TRAP(); + + return; + } + else + { + XDrawSegments(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XSegment *) pSegments, nSegments); + + SET_GC_TRAP(); + fbPolySegment(pDrawable, pGC, nSegments, pSegments); + RESET_GC_TRAP(); + } +} + +void nxagentPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, + int nRectangles, xRectangle *pRectangles) +{ + #ifdef TEST + + if (nRectangles == 1) + { + fprintf(stderr, "nxagentPolyRectangle: Drawable at [%p] GC at [%p] Rectangle [%d,%d][%d,%d].\n", + (void *) pDrawable, (void *) pGC, + pRectangles -> x, pRectangles -> y, pRectangles -> width, pRectangles -> height); + } + else + { + fprintf(stderr, "nxagentPolyRectangle: Drawable at [%p] GC at [%p] Rectangles [%d].\n", + (void *) pDrawable, (void *) pGC, nRectangles); + } + + #endif + + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + miPolyRectangle(nxagentVirtualDrawable(pDrawable), pGC, nRectangles, pRectangles); + } + else + { + miPolyRectangle(pDrawable, pGC, nRectangles, pRectangles); + } + + return; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to poly rectangle on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly rectangle enters with virtual pixmap = [%p] parent is = [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XDrawRectangles(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), (XRectangle *) pRectangles, nRectangles); + } + } + else + { + XDrawRectangles(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XRectangle *) pRectangles, nRectangles); + } + + SET_GC_TRAP(); + + miPolyRectangle(nxagentVirtualDrawable(pDrawable), pGC, nRectangles, pRectangles); + + RESET_GC_TRAP(); + + return; + } + else + { + XDrawRectangles(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XRectangle *) pRectangles, nRectangles); + + SET_GC_TRAP(); + + miPolyRectangle(pDrawable, pGC, nRectangles, pRectangles); + + RESET_GC_TRAP(); + } +} + +void nxagentPolyArc(DrawablePtr pDrawable, GCPtr pGC, + int nArcs, xArc *pArcs) +{ + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + fbPolyArc(nxagentVirtualDrawable(pDrawable), pGC, nArcs, pArcs); + } + else + { + fbPolyArc(pDrawable, pGC, nArcs, pArcs); + } + + return; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to poly arc on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly arc enters with virtual pixmap = [%p] parent is = [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XDrawArcs(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), (XArc *) pArcs, nArcs); + } + } + else + { + XDrawArcs(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XArc *) pArcs, nArcs); + } + + fbPolyArc(nxagentVirtualDrawable(pDrawable), pGC, nArcs, pArcs); + + return; + } + else + { + XDrawArcs(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XArc *) pArcs, nArcs); + + fbPolyArc(pDrawable, pGC, nArcs, pArcs); + } +} + +void nxagentFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int nPoints, xPoint *pPoints) +{ + xPoint *newPoints = NULL; + + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + miFillPolygon(nxagentVirtualDrawable(pDrawable), pGC, shape, mode, nPoints, pPoints); + } + else + { + miFillPolygon(pDrawable, pGC, shape, mode, nPoints, pPoints); + } + + return; + } + + /* + * The coordinate-mode must be CoordModePrevious + * to make better use of differential encoding of + * X_FillPoly request by the side of proxy. + */ + + if (mode == CoordModeOrigin) + { + int i; + + mode = CoordModePrevious; + + newPoints = malloc(nPoints * sizeof(xPoint)); + + /* + * The first point is always relative + * to the drawable's origin. + */ + + newPoints[0].x = pPoints[0].x; + newPoints[0].y = pPoints[0].y; + + /* + * If coordinate-mode is CoordModePrevious, + * the points following the first are rela- + * tive to the previous point. + */ + + for (i = 1; i < nPoints; i++) + { + newPoints[i].x = pPoints[i].x - pPoints[i-1].x; + newPoints[i].y = pPoints[i].y - pPoints[i-1].y; + } + + pPoints = newPoints; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to fill polygon on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: fill polygon enters with virtual pixmap = [%p] parent is = [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XFillPolygon(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), (XPoint *) pPoints, nPoints, shape, mode); + } + } + else + { + XFillPolygon(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XPoint *) pPoints, nPoints, shape, mode); + } + + SET_GC_TRAP(); + + miFillPolygon(nxagentVirtualDrawable(pDrawable), pGC, shape, mode, nPoints, pPoints); + + RESET_GC_TRAP(); + } + else + { + XFillPolygon(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XPoint *) pPoints, nPoints, shape, mode); + + SET_GC_TRAP(); + + miFillPolygon(pDrawable, pGC, shape, mode, nPoints, pPoints); + + RESET_GC_TRAP(); + } + + if (newPoints != NULL) + { + free(newPoints); + } +} + +void nxagentPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, + int nRectangles, xRectangle *pRectangles) +{ + RegionPtr rectRegion; + + int inheritCorruptedRegion; + + #ifdef TEST + + if (nRectangles == 1) + { + fprintf(stderr, "nxagentPolyFillRect: Drawable at [%p] GC at [%p] FillStyle [%d] Rectangle [%d,%d][%d,%d].\n", + (void *) pDrawable, (void *) pGC, pGC -> fillStyle, + pRectangles -> x, pRectangles -> y, pRectangles -> width, pRectangles -> height); + } + else + { + fprintf(stderr, "nxagentPolyFillRect: Drawable at [%p] GC at [%p] FillStyle [%d] Rectangles [%d].\n", + (void *) pDrawable, (void *) pGC, pGC -> fillStyle, nRectangles); + } + + #endif + + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + fbPolyFillRect(nxagentVirtualDrawable(pDrawable), pGC, nRectangles, pRectangles); + } + else + { + fbPolyFillRect(pDrawable, pGC, nRectangles, pRectangles); + } + + return; + } + + /* + * The PolyFillRect acts in two ways: if the GC + * has a corrupted tile, the operation propagates + * the corrupted region on the destination. In + * other cases, because the PolyFillRect will + * cover the destination, any corrupted region + * intersecting the target will be cleared. + */ + + inheritCorruptedRegion = 0; + + if (pGC -> fillStyle == FillTiled && + pGC -> tileIsPixel == 0 && pGC -> tile.pixmap != NULL) + { + nxagentIncreasePixmapUsageCounter(pGC -> tile.pixmap); + + if (nxagentDrawableStatus((DrawablePtr) pGC -> tile.pixmap) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentPolyFillRect: GC at [%p] uses corrupted tile pixmap at [%p]. Going to " + "corrupt the destination [%s][%p].\n", (void *) pGC, (void *) pGC -> tile.pixmap, + (pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), (void *) pDrawable); + + #endif + + inheritCorruptedRegion = 1; + } + } + + if (inheritCorruptedRegion == 1 || nxagentDrawableStatus(pDrawable) == NotSynchronized) + { + rectRegion = RegionFromRects(nRectangles, pRectangles, CT_REGION); + + if (pGC -> clientClip != NULL) + { + RegionRec tmpRegion; + + RegionInit(&tmpRegion, NullBox, 1); + + RegionCopy(&tmpRegion, ((RegionPtr) pGC -> clientClip)); + + if (pGC -> clipOrg.x != 0 || pGC -> clipOrg.y != 0) + { + RegionTranslate(&tmpRegion, pGC -> clipOrg.x, pGC -> clipOrg.y); + } + + RegionIntersect(rectRegion, rectRegion, &tmpRegion); + + RegionUninit(&tmpRegion); + } + + if (inheritCorruptedRegion == 1) + { + /* + * The fill style should affect the cor- + * rupted region propagation: if the tile + * is not completely corrupted the region + * should be 'tiled' over the destination. + */ + + nxagentMarkCorruptedRegion(pDrawable, rectRegion); + } + else + { + if (pGC -> fillStyle != FillStippled && pGC -> fillStyle != FillOpaqueStippled) + { + nxagentUnmarkCorruptedRegion(pDrawable, rectRegion); + } + else + { + /* + * The stipple mask computation could cause + * an high fragmentation of the destination + * region. An analysis should be done to exa- + * mine the better solution (e.g.rdesktop + * uses stipples to draw texts). + */ + + #ifdef TEST + fprintf(stderr, "nxagentPolyFillRect: Synchronizing the region [%d,%d,%d,%d] before using " + "the stipple at [%p].\n", rectRegion -> extents.x1, rectRegion -> extents.y1, + rectRegion -> extents.x2, rectRegion -> extents.y2, (void *) pGC -> stipple); + #endif + + nxagentSynchronizeRegion(pDrawable, rectRegion, NEVER_BREAK, NULL); + } + } + + RegionDestroy(rectRegion); + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to poly fill rect on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly fill rect enters with virtual pixmap = [%p] parent is = [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XFillRectangles(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), (XRectangle *) pRectangles, nRectangles); + } + } + else + { + XFillRectangles(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XRectangle *) pRectangles, nRectangles); + } + + fbPolyFillRect(nxagentVirtualDrawable(pDrawable), pGC, nRectangles, pRectangles); + + return; + } + else + { + XFillRectangles(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XRectangle *) pRectangles, nRectangles); + + fbPolyFillRect(pDrawable, pGC, nRectangles, pRectangles); + } +} + +void nxagentPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, + int nArcs, xArc *pArcs) +{ + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + miPolyFillArc(nxagentVirtualDrawable(pDrawable), pGC, nArcs, pArcs); + } + else + { + miPolyFillArc(pDrawable, pGC, nArcs, pArcs); + } + + return; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to poly fillarc on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly fill arc enters with virtual pixmap = [%p] parent is = [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XFillArcs(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), (XArc *) pArcs, nArcs); + } + } + else + { + XFillArcs(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + (XArc *) pArcs, nArcs); + } + + SET_GC_TRAP(); + + miPolyFillArc(nxagentVirtualDrawable(pDrawable), pGC, nArcs, pArcs); + + RESET_GC_TRAP(); + + return; + } + else + { + XFillArcs(nxagentDisplay, nxagentDrawable(pDrawable), + nxagentGC(pGC), (XArc *) pArcs, nArcs); + + SET_GC_TRAP(); + + miPolyFillArc(pDrawable, pGC, nArcs, pArcs); + + RESET_GC_TRAP(); + } +} + +int nxagentPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, int count, char *string) +{ + int width; + + /* + * While the session is suspended + * the font structure is NULL. + */ + + if (nxagentFontStruct(pGC -> font) == NULL) + { + return x; + } + + width = XTextWidth(nxagentFontStruct(pGC->font), string, count); + + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + miPolyText8(nxagentVirtualDrawable(pDrawable), pGC, x, y, count, string); + } + else + { + miPolyText8(pDrawable, pGC, x, y, count, string); + } + + return width + x; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to poly text8 on FB pixmap [%p] with string [%s].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable), (char *) string); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly text8 enters with virtual pixmap [%p] parent is [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XDrawString(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), x, y, string, count); + } + } + else + { + XDrawString(nxagentDisplay, nxagentDrawable(pDrawable), + nxagentGC(pGC), x, y, string, count); + } + + miPolyText8(nxagentVirtualDrawable(pDrawable), pGC, x, y, count, string); + + return width + x; + } + else + { + XDrawString(nxagentDisplay, nxagentDrawable(pDrawable), nxagentGC(pGC), + x, y, string, count); + + miPolyText8(pDrawable, pGC, x, y, count, string); + } + + return width + x; +} + +int nxagentPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, int count, unsigned short *string) +{ + int width; + + /* + * While the session is suspended + * the font structure is NULL. + */ + + if (nxagentFontStruct(pGC -> font) == NULL) + { + return x; + } + + width = XTextWidth16(nxagentFontStruct(pGC->font), (XChar2b *)string, count); + + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + miPolyText16(nxagentVirtualDrawable(pDrawable), pGC, x, y, count, string); + } + else + { + miPolyText16(pDrawable, pGC, x, y, count, string); + } + + return width + x; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to poly text16 on FB pixmap %p] with string [%s]\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable), (char *) string); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly text16 enters with virtual pixmap = [%p] parent is = [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XDrawString16(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), x, y, (XChar2b *)string, count); + } + } + else + { + XDrawString16(nxagentDisplay, nxagentDrawable(pDrawable), + nxagentGC(pGC), x, y, (XChar2b *)string, count); + } + + miPolyText16(nxagentVirtualDrawable(pDrawable), pGC, x, y, count, string); + + return width + x; + } + else + { + XDrawString16(nxagentDisplay, nxagentDrawable(pDrawable), + nxagentGC(pGC), x, y, (XChar2b *)string, count); + + miPolyText16(pDrawable, pGC, x, y, count, string); + } + + return width + x; +} + +void nxagentImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, int count, char *string) +{ + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + miImageText8(nxagentVirtualDrawable(pDrawable), pGC, x, y, count, string); + } + else + { + miImageText8(pDrawable, pGC, x, y, count, string); + } + + return; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to image text8 on FB pixmap [%p] with string [%s].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable), string); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly image text8 enters with virtual pixmap [%p] parent is [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XDrawImageString(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), x, y, string, count); + } + } + else + { + XDrawImageString(nxagentDisplay, nxagentDrawable(pDrawable), + nxagentGC(pGC), x, y, string, count); + } + + miImageText8(nxagentVirtualDrawable(pDrawable), pGC, x, y, count, string); + + return; + } + else + { + XDrawImageString(nxagentDisplay, nxagentDrawable(pDrawable), + nxagentGC(pGC), x, y, string, count); + + miImageText8(pDrawable, pGC, x, y, count, string); + } +} + +void nxagentImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, int count, unsigned short *string) +{ + if (nxagentGCTrap == 1) + { + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + miImageText16(nxagentVirtualDrawable(pDrawable), pGC, x, y, count, string); + } + else + { + miImageText16(pDrawable, pGC, x, y, count, string); + } + + return; + } + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to image text16 on FB pixmap [%p] with string [%s].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable), (char *) string); + #endif + + if (nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "GCOps: poly image text16 enters with virtual pixmap = [%p] parent is = [%p]\n", + (void *) nxagentVirtualDrawable(pDrawable), + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + if (nxagentRealPixmap((PixmapPtr) pDrawable)) + { + XDrawImageString16(nxagentDisplay, nxagentDrawable((DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable)), + nxagentGC(pGC), x, y, (XChar2b *)string, count); + } + } + else + { + XDrawImageString16(nxagentDisplay, nxagentDrawable(pDrawable), + nxagentGC(pGC), x, y, (XChar2b *)string, count); + } + + miImageText16(nxagentVirtualDrawable(pDrawable), pGC, x, y, count, string); + + return; + } + else + { + XDrawImageString16(nxagentDisplay, nxagentDrawable(pDrawable), + nxagentGC(pGC), x, y, (XChar2b *)string, count); + + miImageText16(pDrawable, pGC, x, y, count, string); + } +} + +void nxagentImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + unsigned int nGlyphs, CharInfoPtr *pCharInfo, + void * pGlyphBase) +{ + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to imageGlyphBlt on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + fbImageGlyphBlt(nxagentVirtualDrawable(pDrawable), pGC, x, y, nGlyphs, pCharInfo, pGlyphBase); + } + else + { + fbImageGlyphBlt(pDrawable, pGC, x, y, nGlyphs, pCharInfo, pGlyphBase); + } +} + +void nxagentPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + unsigned int nGlyphs, CharInfoPtr *pCharInfo, + void * pGlyphBase) +{ + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to PolyGlyphBlt on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + fbPolyGlyphBlt(nxagentVirtualDrawable(pDrawable), pGC, x, y, nGlyphs, pCharInfo, pGlyphBase); + } + else + { + fbPolyGlyphBlt(pDrawable, pGC, x, y, nGlyphs, pCharInfo, pGlyphBase); + } +} + +void nxagentPushPixels(GCPtr pGC, PixmapPtr pBitmap, DrawablePtr pDrawable, + int width, int height, int x, int y) +{ + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "GCOps: GC [%p] going to PushPixels on FB pixmap [%p].\n", + (void *) pGC, (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + fbPushPixels(pGC, nxagentVirtualPixmap(pBitmap), + (DrawablePtr) nxagentVirtualDrawable(pDrawable), + width, height, x, y); + } + else + { + fbPushPixels(pGC, nxagentVirtualPixmap(pBitmap), + (DrawablePtr) pDrawable, width, height, x, y); + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/GCOps.h b/nx-X11/programs/Xserver/hw/nxagent/GCOps.h new file mode 100644 index 000000000..bbf7fa3df --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/GCOps.h @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __GCOps_H__ +#define __GCOps_H__ + +/* + * Graphic operations. + */ + +void nxagentFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nSpans, + xPoint *pPoints, int *pWidths, int fSorted); + +void nxagentSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *pSrc, + xPoint *pPoints, int *pWidths, int nSpans, int fSorted); + +void nxagentGetSpans(DrawablePtr pDrawable, int maxWidth, xPoint *pPoints, + int *pWidths, int nSpans, char *pBuffer); + +RegionPtr nxagentCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, int srcx, int srcy, int width, + int height, int dstx, int dsty); + +RegionPtr nxagentCopyPlane(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, int srcx, int srcy, int width, int height, + int dstx, int dsty, unsigned long plane); + +void nxagentQueryBestSize(int class, unsigned short *pwidth, + unsigned short *pheight, ScreenPtr pScreen); + +void nxagentPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, + int nPoints, xPoint *pPoints); + +void nxagentPolyLines(DrawablePtr pDrawable, GCPtr pGC, int mode, + int nPoints, xPoint *pPoints); + +void nxagentPolySegment(DrawablePtr pDrawable, GCPtr pGC, + int nSegments, xSegment *pSegments); + +void nxagentPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, + int nRectangles, xRectangle *pRectangles); + +void nxagentPolyArc(DrawablePtr pDrawable, GCPtr pGC, + int nArcs, xArc *pArcs); + +void nxagentFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, + int mode, int nPoints, xPoint *pPoints); + +void nxagentPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, + int nRectangles, xRectangle *pRectangles); + +void nxagentPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, + int nArcs, xArc *pArcs); + +int nxagentPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, int count, char *string); + +int nxagentPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, int count, unsigned short *string); + +void nxagentImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, int count, char *string); + +void nxagentImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, int count, unsigned short *string); + +void nxagentImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + unsigned int nGlyphs, CharInfoPtr *pCharInfo, void * pGlyphBase); + +void nxagentPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + unsigned int nGlyphs, CharInfoPtr *pCharInfo, void * pGlyphBase); + +void nxagentPushPixels(GCPtr pGC, PixmapPtr pBitmap, DrawablePtr pDrawable, + int width, int height, int x, int y); + +#endif /* __GCOps_H__ */ + diff --git a/nx-X11/programs/Xserver/hw/nxagent/GCs.h b/nx-X11/programs/Xserver/hw/nxagent/GCs.h new file mode 100644 index 000000000..84b0063ab --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/GCs.h @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __GC_H__ +#define __GC_H__ + +extern RESTYPE RT_NX_GC; + +/* This file uses the GC definition form Xlib.h as XlibGC. */ + +typedef struct { + XlibGC gc; + + int nClipRects; + + XGCValues lastServerValues; + + XID mid; + + PixmapPtr pPixmap; + +} nxagentPrivGC; + +extern int nxagentGCPrivateIndex; + +typedef struct _nxagentGraphicContextsRec +{ + int depth; + GCPtr pGC; + int dirty; + +} nxagentGraphicContextsRec; + +typedef nxagentGraphicContextsRec *nxagentGraphicContextsPtr; +extern nxagentGraphicContextsPtr nxagentGraphicContexts; +extern int nxagentGraphicContextsSize; + +#define nxagentGCPriv(pGC) \ + ((nxagentPrivGC *)((pGC) -> devPrivates[nxagentGCPrivateIndex].ptr)) + +#define nxagentGC(pGC) (nxagentGCPriv(pGC) -> gc) + +#define nxagentCopyGCPriv(valueMask, valueField, src, mask, dst) \ +\ + if (mask & valueMask) \ + { \ + nxagentGCPriv(dst) -> lastServerValues.valueField = \ + nxagentGCPriv(src) -> lastServerValues.valueField; \ + } + +#define nxagentTestGC(newValue, pvalue) \ +\ + ((nxagentGCPriv(pGC) -> lastServerValues.pvalue == newValue) ? 0 : 1); \ +\ + nxagentGCPriv(pGC) -> lastServerValues.pvalue = newValue + +Bool nxagentCreateGC(GCPtr pGC); +void nxagentValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable); +void nxagentChangeGC(GCPtr pGC, unsigned long mask); +void nxagentCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +void nxagentDestroyGC(GCPtr pGC); +void nxagentChangeClip(GCPtr pGC, int type, void * pValue, int nRects); +void nxagentDestroyClip(GCPtr pGC); +void nxagentDestroyClipHelper(GCPtr pGC); +void nxagentCopyClip(GCPtr pGCDst, GCPtr pGCSrc); + +void nxagentDisconnectGC(void * p0, XID x1, void * p2); +Bool nxagentDisconnectAllGCs(void); + +Bool nxagentReconnectAllGCs(void *p0); + +int nxagentDestroyNewGCResourceType(void * p, XID id); + +void nxagentFreeGCList(void); +void nxagentInitGCSafeVector(void); + +GCPtr nxagentGetScratchGC(unsigned depth, ScreenPtr pScreen); +void nxagentFreeScratchGC(GCPtr pGC); + +GCPtr nxagentGetGraphicContext(DrawablePtr pDrawable); +void nxagentAllocateGraphicContexts(void); + +#endif /* __GC_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Handlers.c b/nx-X11/programs/Xserver/hw/nxagent/Handlers.c new file mode 100644 index 000000000..634f7aafd --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Handlers.c @@ -0,0 +1,1325 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "dixstruct.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "osdep.h" + +#include "Agent.h" +#include "Handlers.h" +#include "Display.h" +#include "Events.h" +#include "Client.h" +#include "Reconnect.h" +#include "Dialog.h" +#include "Drawable.h" +#include "Splash.h" +#include "Screen.h" +#include "Millis.h" + +#define Window XlibWindow +#include "compext/Compext.h" +#undef Window + +#include <nx/Shadow.h> + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +/* + * Log begin and end of the important + * handlers. + */ + +#undef BLOCKS + +/* + * If not defined, flush immediately + * upon entering the block handler. + */ + +#define FLUSH_AFTER_MULTIPLE_READS + +/* + * The soft limit should roughly match + * the size of the Xlib I/O buffer. + */ + +#define BYTES_BEFORE_SOFT_TOKEN 2048 +#define BYTES_BEFORE_HARD_TOKEN 65536 + +/* + * Maximum number of synchronization + * requests before waiting for the + * remote. + */ + +#define TOKENS_PENDING_LIMIT 8 + +/* + * Limits are very unobtrusive. We don't + * want to interfere with the normal + * dispatching. + */ + +#define BYTES_BEFORE_YIELD 1048576 +#define TIME_BEFORE_YIELD 500 + +/* + * Dinamically reduce the display buffer + * size after a congestion. + */ + +#undef DYNAMIC_DISPLAY_BUFFER + +/* + * Minimum display buffer size. + */ + +#define MINIMUM_DISPLAY_BUFFER 512 + +#ifdef NX_DEBUG_INPUT +extern int nxagentDebugInputDevices; +extern unsigned long nxagentLastInputDevicesDumpTime; + +extern void nxagentDumpInputDevicesState(void); +#endif + +/* + * Used in the handling of the X desktop + * manager protocol. + */ + +int nxagentXdmcpUp = 0; +int nxagentXdmcpAlertUp = 0; + +/* + * Also used in the block, wakeup and + * sync handlers. + */ + +int nxagentBuffer; +int nxagentBlocking; +int nxagentCongestion; + +double nxagentBytesIn; +double nxagentBytesOut; + +/* + * Total number of descriptors ready + * as reported by the wakeup handler. + */ + +int nxagentReady; + +/* + * Timestamp of the last write to the + * remote display. + */ + +int nxagentFlush; + +/* + * Arbitrate the bandwidth among our + * clients. + */ + +struct _TokensRec nxagentTokens = { 0, 0, 0 }; +struct _DispatchRec nxagentDispatch = { UNDEFINED, 0, 0, 0 }; + +/* + * Called just before blocking, waiting + * for our clients or the X server. + */ + +extern int nxagentSkipImage; + +void nxagentBlockHandler(void * data, struct timeval **timeout, void * mask) +{ + /* + * Zero timeout. + */ + + static struct timeval zero; + + /* + * Current timestamp. + */ + + static int now; + + /* + * Pending bytes to write to the + * network. + */ + + static int flushable; + + /* + * Set if we need to synchronize + * any drawable. + */ + + static int synchronize; + + #ifdef BLOCKS + fprintf(stderr, "[Begin block]\n"); + #endif + + now = GetTimeInMillis(); + + #ifdef NX_DEBUG_INPUT + + if (nxagentDebugInputDevices == 1 && + now - nxagentLastInputDevicesDumpTime > 5000) + { + nxagentLastInputDevicesDumpTime = now; + + nxagentDumpInputDevicesState(); + } + + #endif + + if (nxagentNeedConnectionChange() == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentBlockHandler: Calling nxagentHandleConnectionChanges " + "with ioError [%d] sigHup [%d].\n", nxagentException.ioError, nxagentException.sigHup); + #endif + + nxagentHandleConnectionChanges(); + } + + if (nxagentOption(Rootless) && + nxagentLastWindowDestroyed && nxagentRootlessDialogPid == 0 && + now > nxagentLastWindowDestroyedTime + 30 * 1000 && !nxagentOption(NoRootlessExit)) + { + #ifdef WARNING + fprintf(stderr, "nxagentBlockHandler: No application running. Closing the session.\n"); + #endif + + nxagentTerminateSession(); + } + + #ifdef TEST + + if (nxagentLastWindowDestroyed == 1) + { + fprintf(stderr, "nxagentBlockHandler: Elapsed time [%lu].\n", + now - nxagentLastWindowDestroyedTime); + } + + #endif + + /* + * Slow down the agent if the session is + * not connected to a valid display. + */ + + if (NXDisplayError(nxagentDisplay) == 1 && nxagentShadowCounter == 0 && nxagentOption(SleepTime) > 0) + { +#ifdef TEST + fprintf(stderr, "nxagentBlockHandler: sleeping for %d milliseconds for slowdown.\n", + nxagentOption(SleepTime)); +#endif + usleep(nxagentOption(SleepTime) * 1000); + + now = GetTimeInMillis(); + } +#ifdef TEST + else if (0 == nxagentOption(SleepTime)) { + fprintf(stderr, "nxagentBlockHandler: not sleeping for slowdown.\n"); + } +#endif + + /* + * Update the shadow display. This is + * only for test purposes. + */ + + #ifdef DUMP + + nxagentPixmapOnShadowDisplay(NULL); + + nxagentFbOnShadowDisplay(); + + #endif + + /* + * We need this here because some window + * configuration changes can be generated + * by the X server outside the control of + * the DIX. + */ + + nxagentFlushConfigureWindow(); + + /* + * Check whether there is any drawable to + * synchronize. + */ + + #ifdef TEST + fprintf(stderr, "nxagentBlockHandler: Checking synchronization at %s with " + "[%d][%d][%d].\n", GetTimeInMillisAsString(), nxagentCorruptedWindows, + nxagentCorruptedBackgrounds, nxagentCorruptedPixmaps); + #endif + + synchronize = (nxagentCorruptedWindows > 0 || + nxagentCorruptedBackgrounds > 0 || + nxagentCorruptedPixmaps > 0); + + /* + * The synchronization function requires a mask as + * parameter: + * + * EVENT_BREAK Breaks if an user input, like + * a key press or a mouse move, + * is detected. + * + * CONGESTION_BREAK Breaks if the congestion beco- + * mes greater than 4. + * + * BLOCKING_BREAK Breaks if the display descript- + * or becomes blocked for write + * during the loop. + * + * ALWAYS_BREAK Any of the previous conditions + * is met. + * + * NEVER_BREAK The loop continues until all + * the drawables are synchronized. + */ + + if (synchronize == 1) + { + /* + * We should not enter the synchronization + * loop if there is any user input pending, + * i.e. if we are in the middle of a scroll + * operation. + */ + + if (nxagentForceSynchronization == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentBlockHandler: Going to force a synchronization at %s.\n", + GetTimeInMillisAsString()); + #endif + + nxagentSynchronizationLoop(NEVER_BREAK); + + nxagentForceSynchronization = 0; + } + else if (nxagentUserInput(NULL) == 0 && + nxagentBlocking == 0 && + nxagentCongestion <= 4) + { + #ifdef TEST + fprintf(stderr, "nxagentBlockHandler: Going to synchronize at %s.\n", + GetTimeInMillisAsString()); + #endif + + nxagentSynchronizationLoop(ALWAYS_BREAK); + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentBlockHandler: Not synchronizing with [%d][%d].\n", + nxagentBlocking, nxagentCongestion); + } + #endif + + /* + * Check if we have more corrupted resources + * and whether the conditions are satisfied + * to continue with the synchronization. + */ + + synchronize = (nxagentCongestion <= 4 && + (nxagentCorruptedWindows > 0 || + nxagentCorruptedBackgrounds > 0 || + nxagentCorruptedPixmaps > 0)); + + if (nxagentSkipImage == 0 && synchronize == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentBlockHandler: Setting a zero timeout with [%d][%d][%d] and " + "congestion [%d].\n", nxagentCorruptedWindows, nxagentCorruptedBackgrounds, + nxagentCorruptedPixmaps, nxagentCongestion); + #endif + + zero.tv_sec = 0; + zero.tv_usec = 0; + + *timeout = &zero; + } + #ifdef TEST + else + { + if (nxagentCorruptedWindows == 0 && + nxagentCorruptedBackgrounds == 0 && + nxagentCorruptedPixmaps == 0) + { + fprintf(stderr, "nxagentBlockHandler: Nothing more to synchronize at %s.\n", + GetTimeInMillisAsString()); + } + else + { + fprintf(stderr, "nxagentBlockHandler: Delaying synchronization with [%d][%d][%d] and " + "congestion [%d].\n", nxagentCorruptedWindows, nxagentCorruptedBackgrounds, + nxagentCorruptedPixmaps, nxagentCongestion); + } + } + #endif + } + + /* + * If the remote X server is blocking, reduce the + * amount of data sent in a single display update + * by reducing the size of the display buffer. + */ + + #ifdef DYNAMIC_DISPLAY_BUFFER + + if (nxagentBlocking == 1 && + nxagentBuffer > MINIMUM_DISPLAY_BUFFER) + { + nxagentBuffer >>= 1; + + if (nxagentBuffer < MINIMUM_DISPLAY_BUFFER) + { + nxagentBuffer = MINIMUM_DISPLAY_BUFFER; + } + + #ifdef TEST + fprintf(stderr, "nxagentDispatchHandler: Reducing the display buffer to [%d] bytes.\n", + nxagentBuffer); + #endif + + NXSetDisplayBuffer(nxagentDisplay, nxagentBuffer); + } + else if (nxagentBuffer < nxagentOption(DisplayBuffer) && + nxagentCongestion == 0) + { + nxagentBuffer = nxagentOption(DisplayBuffer); + + #ifdef TEST + fprintf(stderr, "nxagentDispatchHandler: Increasing the display buffer to [%d] bytes.\n", + nxagentBuffer); + #endif + + NXSetDisplayBuffer(nxagentDisplay, nxagentBuffer); + } + + #endif /* #ifdef DYNAMIC_DISPLAY_BUFFER */ + + /* + * Dispatch to the clients the events that + * may have become available. + */ + + if (nxagentPendingEvents(nxagentDisplay) > 0) + { + #ifdef TEST + fprintf(stderr, "nxagentBlockHandler: Reading the events available.\n"); + #endif + + nxagentDispatchEvents(NULL); + } + + /* + * Check if there is any data remaining, + * either in the display buffer or in + * the NX transport. + */ + + flushable = NXDisplayFlushable(nxagentDisplay); + + if (flushable > 0) + { + #ifdef FLUSH_AFTER_MULTIPLE_READS + + /* + * Flush all the outstanding data if + * the wakeup handler didn't detect + * any activity. + */ + + if (nxagentReady == 0 || now - nxagentFlush >= + nxagentOption(DisplayCoalescence)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentBlockHandler: Flushing the display with [%d] bytes to flush.\n", + flushable); + #endif + + NXFlushDisplay(nxagentDisplay, NXFlushLink); + + /* + * New events may have become available + * after the flush. + */ + + if (nxagentPendingEvents(nxagentDisplay) > 0) + { + #ifdef TEST + fprintf(stderr, "nxagentBlockHandler: Reading the events available.\n"); + #endif + + nxagentDispatchEvents(NULL); + } + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentBlockHandler: Delaying flush with [%d][%d] and [%d] bytes.\n", + synchronize, nxagentReady, flushable); + #endif + + zero.tv_sec = 0; + zero.tv_usec = 0; + + *timeout = &zero; + } + + #else /* #ifdef FLUSH_AFTER_MULTIPLE_READS */ + + /* + * We are entering the select. Tell the NX + * transport to write any produced data to + * the remote end. + */ + + NXFlushDisplay(nxagentDisplay, NXFlushLink); + + if (nxagentPendingEvents(nxagentDisplay) > 0) + { + #ifdef TEST + fprintf(stderr, "nxagentBlockHandler: Reading the events available.\n"); + #endif + + nxagentDispatchEvents(NULL); + } + + #endif /* #ifdef FLUSH_AFTER_MULTIPLE_READS */ + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentBlockHandler: Nothing to flush with [%d][%d].\n", + synchronize, nxagentReady); + #endif + + if (NXDisplayError(nxagentDisplay) == 0 && + nxagentQueuedEvents(nxagentDisplay) > 0) + { + #ifdef WARNING + fprintf(stderr, "nxagentBlockHandler: WARNING! Forcing a null timeout with events queued.\n"); + #endif + + zero.tv_sec = 0; + zero.tv_usec = 0; + + *timeout = &zero; + } + } + + /* + * WaitForSomething() sets a zero timeout if there + * are clients with input, but doesn't stop the + * timer. The select is then interrupted to update + * the schedule time even if, what the dispatcher + * cares, is only the number of ticks at the time + * the client is scheduled in. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentBlockHandler: Stopping the smart schedule timer.\n"); + #endif + + nxagentStopTimer(); + + nxagentPrintGeometry(); + + #ifdef BLOCKS + fprintf(stderr, "[End block]\n"); + #endif +} + +void nxagentWakeupHandler(void * data, int count, void * mask) +{ + #ifdef BLOCKS + fprintf(stderr, "[Begin wakeup]\n"); + #endif + + if (nxagentException.sigHup || nxagentException.ioError) + { + #ifdef TEST + fprintf(stderr,"nxagentWakeupHandler: Got SIGHUP or I/O error.\n"); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentBlockHandler: Calling nxagentHandleConnectionStates " + "with ioError [%d] sigHup [%d].\n", nxagentException.ioError, nxagentException.sigHup); + #endif + + nxagentHandleConnectionStates(); + } + + if (!SmartScheduleSignalEnable) + { + + #ifdef DEBUG + fprintf(stderr, "nxagentWakeupHandler: Resetting the dispatch state after wakeup.\n"); + #endif + + nxagentDispatch.start = GetTimeInMillis(); + + nxagentDispatch.in = nxagentBytesIn; + nxagentDispatch.out = nxagentBytesOut; + + } + + /* + * Can become true during the dispatch loop. + */ + + nxagentBlocking = 0; + + /* + * Check if we got new events. + */ + + if (count > 0 && FD_ISSET(nxagentXConnectionNumber, (fd_set *) mask)) + { + #ifdef TEST + fprintf(stderr, "nxagentWakeupHandler: Reading the X events with count [%d].\n", + count); + #endif + + nxagentDispatchEvents(NULL); + + #ifdef TEST + fprintf(stderr, "nxagentWakeupHandler: Removing the X descriptor from the count.\n"); + #endif + + FD_CLR(nxagentXConnectionNumber, (fd_set *) mask); + + count--; + } + else if (nxagentQueuedEvents(nxagentDisplay) == 1) + { + /* + * We may have left some events in + * the queue. + */ + + #ifdef TEST + fprintf(stderr, "nxagentWakeupHandler: Reading the queued X events with count [%d].\n", + count); + #endif + + nxagentDispatchEvents(NULL); + } + + /* + * Save the number of descriptors ready. + */ + + if (count <= 0) + { + count = (XFD_ANYSET(&ClientsWithInput) ? 1 : 0); + } + + nxagentReady = count; + + #ifdef TEST + + if (nxagentReady == 0) + { + fprintf(stderr, "nxagentWakeupHandler: No X clients found to be processed.\n"); + } + + #endif + + /* + * If the XDM connection can't be established + * we'll need to create a dialog to notify the + * user and give him/her a chance to terminate + * the session. + */ + + if (nxagentOption(Xdmcp) == 1 && nxagentXdmcpUp == 0) + { + #ifdef DEBUG + fprintf(stderr, "nxagentWakeupHandler: XdmcpState [%d].\n", XdmcpState); + #endif + + if (XdmcpState == XDM_RUN_SESSION) + { + nxagentXdmcpUp = 1; + } + + if (nxagentXdmcpUp == 0) + { + #ifdef DEBUG + fprintf(stderr, "nxagentWakeupHandler: XdmcpTime [%lu].\n", + GetTimeInMillis() - XdmcpStartTime); + #endif + + #ifdef DEBUG + fprintf(stderr, "nxagentWakeupHandler: XdmcpTimeOutRtx [%d].\n", + XdmcpTimeOutRtx); + #endif + + if (nxagentXdmcpAlertUp == 0 && + GetTimeInMillis() - XdmcpStartTime >= XDM_TIMEOUT) + { + #ifdef WARNING + fprintf(stderr, "nxagentWakeupHandler: WARNING! The XDM session seems to be " + "unable to start after [%ld] ms.\n",(long int)(GetTimeInMillis() - XdmcpStartTime)); + #endif + + NXTransAlert(FAILED_XDMCP_CONNECTION_ALERT, NX_ALERT_REMOTE); + + nxagentXdmcpAlertUp = 1; + } + } + } + + #ifdef BLOCKS + fprintf(stderr, "[End wakeup]\n"); + #endif +} + +void nxagentShadowBlockHandler(void * data, struct timeval **timeout, void * mask) +{ + static struct timeval zero; + + int changed; + int suspended = 0; + int width_, height_; + + #ifdef BLOCKS + fprintf(stderr, "[Begin block]\n"); + #endif + + if (nxagentNeedConnectionChange() == 1) + { + nxagentHandleConnectionChanges(); + } + + if (nxagentSessionState == SESSION_DOWN && nxagentOption(SleepTime) > 0) + { +#ifdef TEST + fprintf(stderr, "nxagentBlockHandler: sleeping for %d milliseconds for slowdown.\n", + nxagentOption(SleepTime)); +#endif + usleep(nxagentOption(SleepTime) * 1000); + } +#ifdef TEST + else if (0 == nxagentOption(SleepTime)) { + fprintf(stderr, "nxagentBlockHandler: not sleeping for slowdown.\n"); + } +#endif + + #ifndef __CYGWIN32__ + + if (nxagentReadEvents(nxagentDisplay) > 0 || + nxagentReadEvents(nxagentShadowDisplay) > 0) + { + #ifdef TEST + fprintf(stderr, "nxagentShadowBlockHandler: Reading X events queued.\n"); + #endif + + nxagentDispatchEvents(NULL); + } + + if (nxagentShadowResize == 1) + { + nxagentShadowResize = 0; + + nxagentShadowAdaptToRatio(); + } + + #else + + if (nxagentReadEvents(nxagentDisplay) > 0) + { + #ifdef TEST + fprintf(stderr, "nxagentShadowBlockHandler: Reading X events queued.\n"); + #endif + + nxagentDispatchEvents(NULL); + } + + #endif + + changed = 0; + + NXShadowGetScreenSize(&width_, &height_); + + if (width_ != nxagentShadowWidth || height_ != nxagentShadowHeight) + { + /* + * The master session has been resized. + */ + + NXShadowSetScreenSize(&nxagentShadowWidth, &nxagentShadowHeight); + + nxagentShadowAdaptToRatio(); + } + + nxagentShadowPoll(nxagentShadowPixmapPtr, nxagentShadowGCPtr, nxagentShadowDepth, nxagentShadowWidth, + nxagentShadowHeight, nxagentShadowBuffer, &changed, &suspended); + + nxagentShadowSendUpdates(&suspended); + + if (nxagentBlocking == 0) + { + nxagentSynchronizeDrawable((DrawablePtr) nxagentShadowPixmapPtr, DONT_WAIT, + ALWAYS_BREAK, nxagentShadowWindowPtr); + } + + /* + * We are entering the select. Tell the NX + * transport to write any produced data to + * the remote end. + */ +/* +FIXME: Must queue multiple writes and handle + the events by resembling the ordinary + block handler. +*/ + + NXFlushDisplay(nxagentDisplay, NXFlushLink); + + if (*timeout == NULL) + { + *timeout = &zero; + } + + #ifdef __CYGWIN32__ + + if (nxagentOption(SleepTime) > 0) { +#ifdef TEST + fprintf(stderr, "nxagentShadowBlockHandler: sleeping for %d milliseconds for slowdown.\n", + nxagentOption(SleepTime)); +#endif + usleep(nxagentOption(SleepTime) * 1000); + } +#ifdef TEST + else if (0 == nxagentOption(SleepTime)) { + fprintf(stderr, "nxagentShadowBlockHandler: not sleeping for slowdown.\n"); + } +#endif + + (*timeout) -> tv_sec = 0; + (*timeout) -> tv_usec = 50 * 1000; + + #else + + if (changed == 0) + { + (*timeout) -> tv_sec = 0; + (*timeout) -> tv_usec = 50 * 1000; + } + else + { + (*timeout) -> tv_sec = 0; + (*timeout) -> tv_usec = 0; + } + + #endif + + nxagentPrintGeometry(); + + #ifdef BLOCKS + fprintf(stderr, "[End block]\n"); + #endif +} + +void nxagentShadowWakeupHandler(void * data, int count, void * mask) +{ + #ifdef BLOCKS + fprintf(stderr, "[Begin wakeup]\n"); + #endif + + if (nxagentException.sigHup || nxagentException.ioError) + { + #ifdef TEST + fprintf(stderr,"nxagentShadowWakeupHandler: Got SIGHUP or I/O error.\n"); + #endif + + nxagentHandleConnectionStates(); + } + + if (!SmartScheduleSignalEnable) + { + + #ifdef DEBUG + fprintf(stderr, "nxagentShadowWakeupHandler: Resetting the dispatch state after wakeup.\n"); + #endif + + nxagentDispatch.start = GetTimeInMillis(); + + nxagentDispatch.in = nxagentBytesIn; + nxagentDispatch.out = nxagentBytesOut; + + } + + /* + * Can become true during the dispatch loop. + */ + + nxagentBlocking = 0; + + /* + * Check if we got new events. + */ + + if (count > 0 && FD_ISSET(nxagentXConnectionNumber, (fd_set *) mask)) + { + #ifdef TEST + fprintf(stderr, "nxagentShadowWakeupHandler: Reading the X events with count [%d].\n", + count); + #endif + + nxagentDispatchEvents(NULL); + + #ifdef TEST + fprintf(stderr, "nxagentShadowWakeupHandler: Removing the X descriptor from the count.\n"); + #endif + + FD_CLR(nxagentXConnectionNumber, (fd_set *) mask); + + count--; + } + else if (nxagentQueuedEvents(nxagentDisplay) == 1) + { + /* + * We may have left some events in + * the queue. + */ + + #ifdef TEST + fprintf(stderr, "nxagentShadowWakeupHandler: Reading the queued X events with count [%d].\n", + count); + #endif + + nxagentDispatchEvents(NULL); + } + + /* + * Save the number of descriptors ready. + */ + + if (count <= 0) + { + count = (XFD_ANYSET(&ClientsWithInput) ? 1 : 0); + } + + nxagentReady = count; + + #ifdef TEST + + if (nxagentReady == 0) + { + fprintf(stderr, "nxagentShadowWakeupHandler: No X clients found to be processed.\n"); + } + + #endif + + #ifdef BLOCKS + fprintf(stderr, "[End wakeup]\n"); + #endif +} + +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 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 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 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. + */ + XlibWindow window; + + int revert_to; + + if (NXGetCollectedInputFocus(nxagentDisplay, resource, &window, &revert_to) == 0) + { + #ifdef PANIC + fprintf(stderr, "nxagentHandleCollectInputFocusEvent: PANIC! Failed to get the input focus " + "reply for resource [%d].\n", resource); + #endif + } + + #ifdef DEBUG + fprintf(stderr, "nxagentHandleCollectInputFocusEvent: Received a sync reply with [%d] pending.\n", + nxagentTokens.pending); + #endif + + nxagentTokens.pending--; + + nxagentCongestion = (nxagentTokens.pending >= TOKENS_PENDING_LIMIT / 2); + + #ifdef TEST + fprintf(stderr, "nxagentHandleCollectInputFocusEvent: Current congestion level is [%d].\n", + nxagentCongestion); + #endif +} + +Bool nxagentCollectInputFocusPredicate(Display *display, XEvent *X, XPointer ptr) +{ + return (X -> xclient.window == 0 && + X -> xclient.message_type == 0 && + X -> xclient.format == 32 && + X -> xclient.data.l[0] == NXCollectInputFocusNotify); +} + +void nxagentDispatchHandler(ClientPtr client, int in, int out) +{ + /* + * This function is called by the dispatcher (with 0 + * bytes out) after a new request has been processed. + * It is also called by the write handler (with 0 + * bytes in) after more data has been written to the + * display. It may be optionally called in the block + * and wakeup handlers. In this case both in and out + * must be 0. + */ + + if (out > 0) + { + /* + * Called by the display write callback. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Called with [%d] bytes written.\n", + out); + #endif + + nxagentBytesOut += out; + + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Total bytes are [%.0f] in [%.0f] out.\n", + nxagentBytesIn, nxagentBytesOut); + #endif + + /* + * Don't take care of the synchronization if + * the NX transport is running. The NX trans- + * port has its own token-based control flow. + * + * We can't produce more output here because + * we are in the middle of the flush. We will + * take care of the sync requests when called + * by the dispatcher. + */ + + if (nxagentOption(LinkType) == LINK_TYPE_NONE) + { + nxagentTokens.soft += out; + + if (out > BYTES_BEFORE_HARD_TOKEN) + { + nxagentTokens.hard += out; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Sync bytes accumulated are [%d] and [%d].\n", + nxagentTokens.soft, nxagentTokens.hard); + #endif + } + + if (!SmartScheduleSignalEnable) + { + + /* + * Pay attention to the next client if this + * client produced enough output. + */ + + if (nxagentBytesOut - nxagentDispatch.out > BYTES_BEFORE_YIELD) + { + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Yielding with [%ld][%.0f][%.0f] for client [%d].\n", + GetTimeInMillis() - nxagentDispatch.start, nxagentBytesIn - nxagentDispatch.in, + nxagentBytesOut - nxagentDispatch.out, nxagentDispatch.client); + #endif + + nxagentDispatch.start = GetTimeInMillis(); + + nxagentDispatch.in = nxagentBytesIn; + nxagentDispatch.out = nxagentBytesOut; + + isItTimeToYield = 1; + } + #ifdef DEBUG + else + { + fprintf(stderr, "nxagentDispatchHandler: Dispatching with [%ld][%.0f][%.0f] for client [%d].\n", + GetTimeInMillis() - nxagentDispatch.start, nxagentBytesIn - nxagentDispatch.in, + nxagentBytesOut - nxagentDispatch.out, nxagentDispatch.client); + } + #endif + + } + + return; + } + else if (in > 0) + { + /* + * Called by the dispatcher. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Called with [%d] bytes processed for client [%d].\n", + in, client -> index); + #endif + + /* + * This is presently unused. + * + * nxagentClientAddBytes(client, in); + * + * #ifdef DEBUG + * fprintf(stderr, "nxagentDispatchHandler: Bytes processed for client [%d] are [%ld].\n", + * client -> index, nxagentClientBytes(client)); + * #endif + * + */ + + nxagentBytesIn += in; + + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Total bytes are [%.0f] in [%.0f] out.\n", + nxagentBytesIn, nxagentBytesOut); + #endif + + /* + * When using the dumb scheduler, before reading from + * another client, the dispatcher tries to drain all + * the input from the client being processed. This + * means that, if isItTimeToYield is never set and the + * client never produces any output, we'll stick into + * the inner dispatch loop forever. + */ + + if (!SmartScheduleSignalEnable) + { + + if (client -> index != nxagentDispatch.client) + { + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Resetting the dispatch state with [%d][%d].\n", + nxagentDispatch.client, client -> index); + #endif + + nxagentDispatch.client = client -> index; + nxagentDispatch.start = GetTimeInMillis(); + + nxagentDispatch.in = nxagentBytesIn; + nxagentDispatch.out = nxagentBytesOut; + } + else + { + static unsigned long int now; + + now = GetTimeInMillis(); + + if (now - nxagentDispatch.start > TIME_BEFORE_YIELD || + nxagentBytesIn - nxagentDispatch.in > BYTES_BEFORE_YIELD) + { + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Yielding with [%ld][%.0f][%.0f] for client [%d].\n", + now - nxagentDispatch.start, nxagentBytesIn - nxagentDispatch.in, nxagentBytesOut - + nxagentDispatch.out, nxagentDispatch.client); + #endif + + nxagentDispatch.start = now; + + nxagentDispatch.in = nxagentBytesIn; + nxagentDispatch.out = nxagentBytesOut; + + isItTimeToYield = 1; + } + #ifdef DEBUG + else + { + fprintf(stderr, "nxagentDispatchHandler: Dispatching with [%ld][%.0f][%.0f] for client [%d].\n", + now - nxagentDispatch.start, nxagentBytesIn - nxagentDispatch.in, nxagentBytesOut - + nxagentDispatch.out, nxagentDispatch.client); + } + #endif + } + + } + + } + + /* + * Let's see if it's time to sync. + */ + + if (nxagentOption(LinkType) == LINK_TYPE_NONE) + { + if (nxagentTokens.hard > BYTES_BEFORE_HARD_TOKEN) + { + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Requesting a hard sync reply with [%d] bytes.\n", + nxagentTokens.hard); + #endif + + XSync(nxagentDisplay, 0); + + if (nxagentPendingEvents(nxagentDisplay) > 0) + { + nxagentDispatchEvents(NULL); + } + + nxagentTokens.soft = 0; + nxagentTokens.hard = 0; + } + else if (nxagentTokens.soft > BYTES_BEFORE_SOFT_TOKEN) + { + /* + * Alternatively, the amounts of bytes + * accounted for each sync request may + * be decreased according to the number + * of pending replies already awaited. + * + * else if (nxagentTokens.soft > (BYTES_BEFORE_SOFT_TOKEN / (nxagentTokens.pending + 1))) + */ + + int resource; + + /* + * Wait eventually for the number of + * synchronization requests to return + * below the limit. + */ + + #ifdef TEST + + if (nxagentTokens.pending == TOKENS_PENDING_LIMIT) + { + fprintf(stderr, "nxagentDispatchHandler: WARNING! Waiting for the synchronization reply.\n"); + } + + #endif + + while (nxagentTokens.pending == TOKENS_PENDING_LIMIT) + { + if (nxagentWaitEvents(nxagentDisplay, NULL) == -1) + { + nxagentTokens.pending = 0; + + nxagentTokens.soft = 0; + + return; + } + + nxagentDispatchEvents(NULL); + + nxagentBlocking = 1; + } + + /* + * Send a new synchronization request. + */ + + resource = nxagentWaitForResource(NXGetCollectInputFocusResource, + nxagentCollectInputFocusPredicate); + + if (resource == -1) + { + #ifdef PANIC + fprintf(stderr, "nxagentDispatchHandler: PANIC! Cannot allocate any valid resource.\n"); + #endif + + nxagentTokens.soft = 0; + + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentDispatchHandler: Requesting a sync reply with [%d] bytes " + "and [%d] pending.\n", nxagentTokens.soft, nxagentTokens.pending); + #endif + + NXCollectInputFocus(nxagentDisplay, resource); + + NXFlushDisplay(nxagentDisplay, NXFlushBuffer); + + if (nxagentPendingEvents(nxagentDisplay) > 0) + { + nxagentDispatchEvents(NULL); + } + + nxagentTokens.pending++; + + nxagentCongestion = (nxagentTokens.pending >= TOKENS_PENDING_LIMIT / 2); + + #ifdef TEST + fprintf(stderr, "nxagentDispatchHandler: Current congestion level is [%d].\n", + nxagentCongestion); + #endif + + nxagentTokens.soft = 0; + } + } + + /* + * Check if there are events to read. + */ + + if (nxagentPendingEvents(nxagentDisplay) > 0) + { + nxagentDispatchEvents(NULL); + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Handlers.h b/nx-X11/programs/Xserver/hw/nxagent/Handlers.h new file mode 100644 index 000000000..ddae097da --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Handlers.h @@ -0,0 +1,129 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Handlers_H__ +#define __Handlers_H__ + +/* + * Current size of the display buffer. + */ + +extern int nxagentBuffer; + +/* + * Set if we had to block waiting for + * the display to become writable. + */ + +extern int nxagentBlocking; + +/* + * Current congestion level based on + * the sync requests awaited or the + * proxy tokens. + */ + +extern int nxagentCongestion; + +/* + * Bytes read from the agent's clients + * and written to the display socket. + */ + +extern double nxagentBytesIn; +extern double nxagentBytesOut; + +/* + * Total number of descriptors ready + * as reported by the wakeup handler. + */ + +extern int nxagentReady; + +/* + * Timestamp of the last write to the + * remote display. + */ + +extern int nxagentFlush; + +/* + * Let the dispatch loop yield control to + * a different client after a fair amount + * of time or after enough data has been + * processed. + */ + +struct _DispatchRec +{ + int client; + + double in; + double out; + + unsigned long start; +}; + +extern struct _DispatchRec nxagentDispatch; + +/* + * Ensure that we synchronize with the X + * server after a given amount of output + * is produced. + */ + +struct _TokensRec +{ + int soft; + int hard; + + int pending; +}; + +extern struct _TokensRec nxagentTokens; + +/* + * The agent's block and wakeup handlers. + */ + +void nxagentBlockHandler(void * data, struct timeval **timeout, void * mask); +void nxagentWakeupHandler(void * data, int count, void * mask); + +/* + * Executed after each request processed. + */ + +void nxagentDispatchHandler(ClientPtr client, int in, int out); + +void nxagentShadowBlockHandler(void * data, struct timeval **timeout, void * mask); +void nxagentShadowWakeupHandler(void * data, int count, void * mask); + +extern GCPtr nxagentShadowGCPtr; +extern unsigned char nxagentShadowDepth; +extern int nxagentShadowWidth; +extern int nxagentShadowHeight; +extern char *nxagentShadowBuffer; + +#endif /* __Handlers_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Holder.c b/nx-X11/programs/Xserver/hw/nxagent/Holder.c new file mode 100644 index 000000000..aae48471b --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Holder.c @@ -0,0 +1,235 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <signal.h> +#include <stdio.h> + +#ifdef _XSERVER64 + +#include "scrnintstr.h" +#include "Agent.h" +#define GC XlibGC +#define Pixmap XlibPixmap +#define PIXEL_ALREADY_TYPEDEFED + +#endif /* _XSERVER64 */ + +#include "pixmapstr.h" +#include "regionstr.h" +#include "resource.h" +#include "../../include/gc.h" +#include "../../include/window.h" + +#include "X11/include/xpm_nxagent.h" + +#include "Agent.h" +#include "Pixmaps.h" +#include "Display.h" +#include "Holder.h" +#include "Icons.h" + +#include NXAGENT_PLACEHOLDER_NAME + +#define MAXDEPTH 32 + +#define PLACEHOLDER_WIDTH 14 +#define PLACEHOLDER_HEIGHT 16 + +#define PLACEHOLDER_BORDER_COLOR_DARK 0x000000 +#define PLACEHOLDER_BORDER_COLOR_LIGHT 0xB2B2B2 + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +static Pixmap nxagentPlaceholderPixmaps[MAXDEPTH + 1]; + +void nxagentMarkPlaceholderNotLoaded(int depth) +{ + nxagentPlaceholderPixmaps[depth] = 0; +} + +void nxagentInitPlaceholder(int depth) +{ + int status; + XpmAttributes attributes; + + attributes.valuemask = XpmDepth | XpmSize; + attributes.depth = depth; + + status = XpmCreatePixmapFromData(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + placeholderXpm, nxagentPlaceholderPixmaps + depth, NULL, &attributes); + + if (status != Success) + { + FatalError("Error: Failed to create the placeholder pixmap.\n"); + } + + #ifdef TEST + fprintf(stderr, "nxagentInitPlaceholder: Created pixmap [0x%lx] with geometry [%d,%d] for depth [%d].\n", + nxagentPlaceholderPixmaps[depth], attributes.width, attributes.height, depth); + #endif +} + +void nxagentApplyPlaceholder(Drawable drawable, int x, int y, + int w, int h, int depth) +{ + /* + * Instead of the image, a white rectangle that + * covers the pixmap area is drawn, alongside + * with a black and grey line that outlines the + * boundaries of the affected area. + */ + + GC gc; + XGCValues value; + XPoint points[3]; + + value.foreground = 0xffffffff; + value.background = 0x00000000; + value.plane_mask = 0xffffffff; + value.fill_style = FillSolid; + + /* + * FIXME: Should we use a gc cache to save + * some bandwidth? + */ + + gc = XCreateGC(nxagentDisplay, drawable, GCBackground | + GCForeground | GCFillStyle | GCPlaneMask, &value); + + XFillRectangle(nxagentDisplay, drawable, gc, x, y, w, h); + + if (depth == 1) + { + return; + } + + value.foreground = PLACEHOLDER_BORDER_COLOR_DARK; + value.line_style = LineSolid; + value.line_width = 1; + + points[0].x = x; + points[0].y = y + h - 1; + points[1].x = x; + points[1].y = y; + points[2].x = x + w - 1; + points[2].y = y; + + XChangeGC(nxagentDisplay, gc, GCForeground | GCLineWidth | GCLineStyle, &value); + XDrawLines(nxagentDisplay, drawable, gc, points, 3, CoordModeOrigin); + + value.foreground = PLACEHOLDER_BORDER_COLOR_LIGHT; + value.line_style = LineSolid; + value.line_width = 1; + + points[0].x = x; + points[0].y = y + h - 1; + points[1].x = x + w - 1; + points[1].y = y + h - 1; + points[2].x = x + w - 1; + points[2].y = y; + + XChangeGC(nxagentDisplay, gc, GCForeground | GCLineWidth | GCLineStyle, &value); + XDrawLines(nxagentDisplay, drawable, gc, points, 3, CoordModeOrigin); + + /* + * We are going to apply place holder only if on region + * we have enough space for the placeholder plus three + * pixel for spacing and one for region border. + */ + + if ((w >= PLACEHOLDER_WIDTH + 8) && (h >= PLACEHOLDER_HEIGHT + 8)) + { + #ifdef TEST + fprintf(stderr, "nxagentApplyPlaceholder: drawable %lx placeholder %lx from %d %d pixmap size is %d %d " + "depth %d\n", drawable, nxagentPlaceholderPixmaps[depth], x, y, w, h, depth); + #endif + + if (nxagentPlaceholderPixmaps[depth] == 0) + { + nxagentInitPlaceholder(depth); + } + + XCopyArea(nxagentDisplay, nxagentPlaceholderPixmaps[depth], + drawable, gc, 0, 0, PLACEHOLDER_WIDTH, PLACEHOLDER_HEIGHT, x + 4, y + 4); + + } + + XFreeGC(nxagentDisplay, gc); + + return; +} + +#ifdef DUMP + +static char hexdigit(char c) +{ + char map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '?'}; + + return map[c]; +} + +/* +FIXME: Please, check the implementation of the same + function in nxcomp. +*/ +char *nxagentChecksum(char *string, int length) +{ + static char md5_output[MD5_DIGEST_LENGTH * 2 + 1]; + static char md5[MD5_DIGEST_LENGTH]; + char * ret; + int i; + + memset(md5, 0, sizeof(md5)); + memset(md5_output, 0, sizeof(md5_output)); + + ret = MD5(string, length, md5); + + for (i = 0; i < MD5_DIGEST_LENGTH; i++) + { + char c = md5[i]; + + md5_output[i * 2 + 0] = hexdigit((c >> 0) & 0xF); + md5_output[i * 2 + 1] = hexdigit((c >> 4) & 0xF); + } + + return md5_output; +} + +#else + +const char *nxagentChecksum(char *data, int size) +{ + return ""; +} + +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/Holder.h b/nx-X11/programs/Xserver/hw/nxagent/Holder.h new file mode 100644 index 000000000..d1378ee03 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Holder.h @@ -0,0 +1,35 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Holder_H__ +#define __Holder_H__ + +void nxagentMarkPlaceholderNotLoaded(int depth); +void nxagentInitPlaceholder(int depth); +void nxagentApplyPlaceholder(Drawable drawable, int x, int y, int w, int h, int depth); + +const char *nxagentChecksum(char *data, int size); + +#endif /* __Holder_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Icons.h b/nx-X11/programs/Xserver/hw/nxagent/Icons.h new file mode 100644 index 000000000..a87a5a112 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Icons.h @@ -0,0 +1,39 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Icons_H__ +#define __Icons_H__ + +#define Pixel XpmPixel +#include "X11/include/xpm_nxagent.h" +#undef Pixel + +#define NXAGENT_ICON_NAME "nxagent.xpm" + +#define X2GOAGENT_ICON_NAME "x2go.xpm" + +#define NXAGENT_PLACEHOLDER_NAME "nxmissing.xpm" + +#endif /* __Icons_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Image.c b/nx-X11/programs/Xserver/hw/nxagent/Image.c new file mode 100644 index 000000000..590f0b249 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Image.c @@ -0,0 +1,1828 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "scrnintstr.h" +#include "resource.h" +#include "dixstruct.h" +#include "../../fb/fb.h" + +#include "Agent.h" +#include "Composite.h" +#include "Display.h" +#include "Visual.h" +#include "Drawable.h" +#include "Pixmaps.h" +#include "GCs.h" +#include "Image.h" +#include "Events.h" +#include "Client.h" +#include "Trap.h" +#include "Split.h" +#include "Args.h" +#include "Screen.h" +#include "Pixels.h" +#include "Utils.h" + +#include "compext/Compext.h" +#include <nx/NXpack.h> + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +/* + * Don't pack the images having a width, a + * height or a data size smaller or equal + * to these thresholds. + */ + +#define IMAGE_PACK_WIDTH 2 +#define IMAGE_PACK_HEIGHT 2 +#define IMAGE_PACK_LENGTH 512 + +/* + * Compress the image with a lossless encoder + * if the percentage of discrete pixels in the + * image is below this threshold. + */ + +#define IMAGE_UNIQUE_RATIO 10 + +/* + * Preferred pack and split parameters we + * got from the NX transport. + */ + +int nxagentPackLossless = -1; +int nxagentPackMethod = -1; +int nxagentPackQuality = -1; +int nxagentSplitThreshold = -1; + +/* + * Set if images can use the alpha channel. + */ + +int nxagentAlphaEnabled = 0; +int nxagentAlphaCompat = 0; + +/* + * Used to reformat image when connecting to + * displays having different byte order. + */ + +extern void nxagentBitOrderInvert(unsigned char *, int); +extern void nxagentTwoByteSwap(unsigned char *, register int); +extern void nxagentFourByteSwap(register unsigned char *, register int); + +/* + * Store the last visual used to unpack + * the images for the given client. + */ + +static VisualID nxagentUnpackVisualId[MAX_CONNECTIONS]; + +/* + * Store the last alpha data set for the + * client. + */ + +typedef struct _UnpackAlpha +{ + char *data; + int size; + +} UnpackAlphaRec; + +typedef UnpackAlphaRec *UnpackAlphaPtr; + +static UnpackAlphaPtr nxagentUnpackAlpha[MAX_CONNECTIONS]; + +/* + * Encode the imade alpha channel by using + * a specific encoding, separating it from + * the rest of the RGB data. + */ + +static char *nxagentImageAlpha(XImage *ximage); +static void nxagentSetUnpackAlpha(DrawablePtr pDrawable, XImage *pImage, ClientPtr pClient); + +/* + * Copy the source data to the destination. + */ + +static char *nxagentImageCopy(XImage *source, XImage *destination); + +/* + * Return true if the image can be cached. + * Don't cache the images packed with the + * bitmap method as the encoding is little + * more expensive than a copy. + */ + +#define nxagentNeedCache(image, method) \ +\ + ((method) != PACK_BITMAP_16M_COLORS) + +/* + * With the bitmap encoding, if the image + * is 32 bits-per-pixel the 4th byte is not + * transmitted, so we don't need to clean + * the image. + */ + +#define nxagentNeedClean(image, method) \ +\ + ((method) == PACK_RLE_16M_COLORS || \ + (method) == PACK_RGB_16M_COLORS || \ + ((method) == PACK_BITMAP_16M_COLORS && \ + image -> bits_per_pixel != 32)) + +/* + * Collect the image cache statistics. + */ + +typedef struct _ImageStatisticsRec +{ + double partialLookups; + double partialMatches; + double partialEncoded; + double partialAdded; + + double totalLookups; + double totalMatches; + double totalEncoded; + double totalAdded; + +} ImageStatisticsRec; + +ImageStatisticsRec nxagentImageStatistics; + +int nxagentImageReformat(char *base, int nbytes, int bpp, int order) +{ + /* + * This is used whenever we need to swap the image data. + * If we got an image from a X server having a different + * endianess, we will need to redormat the image to match + * our own image-order so that ProcGetImage can return + * the expected format to the client. + */ + + switch (bpp) + { + case 1: + { + if (BITMAP_BIT_ORDER != order) + { + #ifdef TEST + fprintf(stderr, "nxagentImageReformat: Bit order invert with size [%d] " + "bits per pixel [%d] byte order [%d].\n", nbytes, bpp, order); + #endif + + nxagentBitOrderInvert((unsigned char *) base, nbytes); + } + + #if IMAGE_BYTE_ORDER != BITMAP_BIT_ORDER && BITMAP_SCANLINE_UNIT != 8 + + nxagentImageReformat(base, nbytes, BITMAP_SCANLINE_UNIT, order); + + #endif + + break; + } + case 4: + case 8: + { + break; + } + case 16: + { + if (IMAGE_BYTE_ORDER != order) + { + #ifdef TEST + fprintf(stderr, "nxagentImageReformat: Two bytes swap with size [%d] " + "bits per pixel [%d] byte order [%d].\n", nbytes, bpp, order); + #endif + + nxagentTwoByteSwap((unsigned char *) base, nbytes); + } + + break; + } + case 32: + { + if (IMAGE_BYTE_ORDER != order) + { + #ifdef TEST + fprintf(stderr, "nxagentImageReformat: Four bytes swap with size [%d] " + "bits per pixel [%d] byte order [%d].\n", nbytes, bpp, order); + #endif + + nxagentFourByteSwap((unsigned char *) base, nbytes); + } + + break; + } + } + + return 1; +} + +int nxagentImageLength(int width, int height, int format, int leftPad, int depth) +{ + int line = 0; + + if (format == XYBitmap) + { + line = BitmapBytePad(width + leftPad); + } + else if (format == XYPixmap) + { + line = BitmapBytePad(width + leftPad); + + line *= depth; + } + else if (format == ZPixmap) + { + line = PixmapBytePad(width, depth); + } + + return line * height; +} + +int nxagentImagePad(int width, int format, int leftPad, int depth) +{ + int line = 0; + + if (format == XYBitmap) + { + line = BitmapBytePad(width + leftPad); + } + else if (format == XYPixmap) + { + line = BitmapBytePad(width + leftPad); + } + else if (format == ZPixmap) + { + line = PixmapBytePad(width, depth); + } + + return line; +} + +/* + * Only copy the data, not the structure. + * The data pointed by the destination is + * lost. Used to clone two images that + * point to the same data. + */ + +char *nxagentImageCopy(XImage *source, XImage *destination) +{ + #ifdef DEBUG + fprintf(stderr, "nxagentImageClone: Copying [%d] bytes of data from the source.\n", + source -> bytes_per_line * source -> height); + #endif + + destination -> data = Xmalloc(source -> bytes_per_line * source -> height); + + if (destination -> data == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentImageCopy: PANIC! Cannot allocate memory for the copy.\n"); + #endif + } + else + { + memcpy(destination -> data, source -> data, + source -> bytes_per_line * source -> height); + } + + return destination -> data; +} + +char *nxagentImageAlpha(XImage *image) +{ + char *pData; + + char *pSrcData; + char *pDstData; + + int size; + int offset; + + /* + * Use one byte per pixel. + */ + + size = (image -> bytes_per_line * image -> height) >> 2; + + pData = Xmalloc(size); + + if (pData == NULL) + { + return NULL; + } + + /* + * The image is supposed to be in + * server order. + */ + + offset = (image -> byte_order == MSBFirst) ? 0 : 3; + + pSrcData = image -> data; + pDstData = pData; + + while (size-- > 0) + { + *pDstData++ = *(pSrcData + offset); + + pSrcData += 4; + } + + return pData; +} + +/* + * Write down the image cache statistics + * to the buffer. + */ + +void nxagentImageStatisticsHandler(char **buffer, int type) +{ +/* +FIXME: Agent cache statistics have to be implemented. +*/ + #ifdef TEST + fprintf(stderr, "nxagentImageStatisticsHandler: STATISTICS! Statistics requested to the agent.\n"); + #endif + + *buffer = NULL; +} + +/* + * This should be called only for drawables + * having a depth of 32. In the other cases, + * it would only generate useless traffic. + */ + +void nxagentSetUnpackAlpha(DrawablePtr pDrawable, XImage *pImage, ClientPtr pClient) +{ + int resource = pClient -> index; + + unsigned int size = (pImage -> bytes_per_line * pImage -> height) >> 2; + + char *data = nxagentImageAlpha(pImage); + + if (data == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentSetUnpackAlpha: PANIC! Can't allocate data for the alpha channel.\n"); + #endif + + return; + } + + /* + * If we are synchronizing the drawable, discard + * any unpack alpha stored for the client. The + * alpha data, in fact, may be still traveling + * and so we either wait until the end of the + * split or send a fresh copy. + */ +/* +FIXME: Here the split trap is always set and so the caching of + the alpha channel is useless. I remember we set the trap + because of the cursor but why is it always set now? +*/ + #ifdef DEBUG + fprintf(stderr, "nxagentSetUnpackAlpha: Checking alpha channel for client [%d] with trap [%d].\n", + resource, nxagentSplitTrap); + #endif + + if (nxagentSplitTrap == 1 || nxagentUnpackAlpha[resource] == NULL || + nxagentUnpackAlpha[resource] -> size != size || + memcmp(nxagentUnpackAlpha[resource] -> data, data, size) != 0) + { + #ifdef DEBUG + fprintf(stderr, "nxagentSetUnpackAlpha: Sending alpha channel with width [%d] height [%d] " + "bytes per line [%d] size [%d].\n", pImage -> width, pImage -> height, + pImage -> bytes_per_line, size); + #endif + + /* + * Check if we are connected to a newer proxy + * version and so can send the alpha data in + * compressed form. + */ + + if (nxagentAlphaCompat == 0) + { + NXSetUnpackAlpha(nxagentDisplay, resource, PACK_NONE, size, data, size); + } + else + { + NXSetUnpackAlphaCompat(nxagentDisplay, resource, size, data); + } + + if (nxagentUnpackAlpha[resource] != NULL) + { + free(nxagentUnpackAlpha[resource] -> data); + } + else if ((nxagentUnpackAlpha[resource] = Xmalloc(sizeof(UnpackAlphaRec))) == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentSetUnpackAlpha: PANIC! Can't allocate data for the alpha structure.\n"); + #endif + + free(data); + + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentSetUnpackAlpha: Saved alpha channel for client [%d] with size [%d].\n", + resource, size); + #endif + + nxagentUnpackAlpha[resource] -> size = size; + nxagentUnpackAlpha[resource] -> data = data; + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentSetUnpackAlpha: Matched alpha channel for client [%d] with size [%d].\n", + resource, size); + #endif + + free(data); + } +} + +/* + * The NX agent's implementation of the + * X server's image functions. + */ + +void nxagentPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int dstX, int dstY, int dstWidth, int dstHeight, + int leftPad, int format, char *data) +{ + int length; + + RegionPtr pRegion = NullRegion; + + int resource = 0; + int split = 0; + int cache = 1; + + #ifdef TEST + fprintf(stderr, "nxagentPutImage: Image data at [%p] drawable [%s][%p] geometry [%d,%d,%d,%d].\n", + data, (pDrawable -> type == DRAWABLE_PIXMAP ? "Pixmap" : "Window"), + (void *) pDrawable, dstX, dstY, dstWidth, dstHeight); + #endif + + /* + * If the display is down and there is not an + * nxagent attached, sleep for a while but + * still give a chance to the client to write + * to the framebuffer. + */ + + length = nxagentImageLength(dstWidth, dstHeight, format, leftPad, depth); + + if (nxagentShadowCounter == 0 && + NXDisplayError(nxagentDisplay) == 1 && + nxagentOption(SleepTime) > 0) + { + int us; + + us = nxagentOption(SleepTime) * 4 * (length / 1024); + + us = (us < 10000 ? 10000 : (us > 1000000 ? 1000000 : us)); + + #ifdef DEBUG + fprintf(stderr, "nxagentPutImage: Sleeping for [%d] milliseconds with length [%d] and link down.\n", + us / 1000, length); + #endif + + usleep(us); + } + + /* + * This is of little use because clients usually write + * to windows only after an expose event, and, in the + * rare case they use a direct put image to the window + * (for a media player it should be a necessity), they + * are likely to monitor the visibility of the window. + */ + + if (nxagentOption(IgnoreVisibility) == 0 && pDrawable -> type == DRAWABLE_WINDOW && + (nxagentWindowIsVisible((WindowPtr) pDrawable) == 0 || + (nxagentDefaultWindowIsVisible() == 0 && nxagentCompositeEnable == 0))) + { + + #ifdef TEST + fprintf(stderr, "nxagentPutImage: WARNING! Prevented operation on fully obscured " + "window at [%p].\n", (void *) pDrawable); + #endif + + goto nxagentPutImageEnd; + } + + /* + * This is more interesting. Check if the operation + * will produce a visible result based on the clip + * list of the window and the GC. + */ + + pRegion = nxagentCreateRegion(pDrawable, pGC, dstX, dstY, dstWidth, dstHeight); + + if (RegionNil(pRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentPutImage: WARNING! Prevented operation on fully clipped " + "region [%d,%d,%d,%d] for drawable at [%p].\n", pRegion -> extents.x1, + pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2, + (void *) pDrawable); + #endif + + goto nxagentPutImageEnd; + } + +/* +FIXME: Should use these. + + int framebuffer = 1; + int realize = 1; +*/ + if (nxagentGCTrap == 1 && nxagentReconnectTrap == 0 && + nxagentFBTrap == 0 && nxagentShmTrap == 0) + { + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + fbPutImage(nxagentVirtualDrawable(pDrawable), pGC, depth, + dstX, dstY, dstWidth, dstHeight, leftPad, format, data); + } + else + { + fbPutImage(pDrawable, pGC, depth, + dstX, dstY, dstWidth, dstHeight, leftPad, format, data); + } + + goto nxagentPutImageEnd; + } + + if (nxagentReconnectTrap == 0 && + nxagentSplitTrap == 0) + { + if (pDrawable -> type == DRAWABLE_PIXMAP && + nxagentFBTrap == 0 && nxagentShmTrap == 0) + { + fbPutImage(nxagentVirtualDrawable(pDrawable), pGC, depth, + dstX, dstY, dstWidth, dstHeight, leftPad, format, data); + } + else if (pDrawable -> type == DRAWABLE_WINDOW) + { + fbPutImage(pDrawable, pGC, depth, + dstX, dstY, dstWidth, dstHeight, leftPad, format, data); + } + } + + /* + * We are going to realize the operation + * on the real display. Let's check if + * the link is down. + */ + + if (NXDisplayError(nxagentDisplay) == 1) + { + goto nxagentPutImageEnd; + } + + /* + * Mark the region as corrupted and skip the operation + * if we went out of bandwidth. The drawable will be + * synchronized at later time. Don't do that if the + * image is likely to be a shape or a clip mask, if we + * are here because we are actually synchronizing the + * drawable or if the drawable's corrupted region is + * over-age. + */ + + if (NXAGENT_SHOULD_DEFER_PUTIMAGE(pDrawable)) + { + if (pDrawable -> type == DRAWABLE_PIXMAP && + pDrawable -> depth != 1 && + nxagentOption(DeferLevel) >= 1) + { + /* -- changed by dimbor (small "bed-sheets" never need be prevented - always put) --*/ + if (dstHeight > 16) + { + /* -------------------------------------------------------------------------------- */ + #ifdef TEST + fprintf(stderr, "nxagentPutImage: WARNING! Prevented operation on region [%d,%d,%d,%d] " + "for drawable at [%p] with drawable pixmap.\n", pRegion -> extents.x1, + pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2, + (void *) pDrawable); + #endif + + nxagentMarkCorruptedRegion(pDrawable, pRegion); + + goto nxagentPutImageEnd; + /* --- changed by dimbor ---*/ + } + /* ------------------------- */ + } + + if (pDrawable -> type == DRAWABLE_WINDOW && + nxagentOption(DeferLevel) >= 2) + { + #ifdef TEST + fprintf(stderr, "nxagentPutImage: WARNING! Prevented operation on region [%d,%d,%d,%d] " + "for drawable at [%p] with drawable window.\n", pRegion -> extents.x1, + pRegion -> extents.y1, pRegion -> extents.x2, pRegion -> extents.y2, + (void *) pDrawable); + #endif + + nxagentMarkCorruptedRegion(pDrawable, pRegion); + + goto nxagentPutImageEnd; + } + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentPutImage: Operation on drawable [%p] not skipped with nxagentSplitTrap [%d].\n", + (void *) pDrawable, nxagentSplitTrap); + } + #endif + + /* + * Check whether we need to enclose the + * image in a split sequence. + */ +/* +FIXME: Should we disable the split with link LAN? + + split = (nxagentOption(Streaming) == 1 && + nxagentOption(LinkType) != LINK_TYPE_NONE && + nxagentOption(LinkType) != LINK_TYPE_LAN +*/ + split = (nxagentOption(Streaming) == 1 && + nxagentOption(LinkType) != LINK_TYPE_NONE +/* +FIXME: Do we stream the images from GLX or Xv? If we do that, + we should also write on the frame buffer, including the + images put on windows, to be able to reconstruct the + region that is out of sync. Surely we should not try to + cache the GLX and Xv images in memory or save them in + the image cache on disk. +*/ +/* +FIXME: Temporarily stream the GLX data. + + && nxagentGlxTrap == 0 + && nxagentXvTrap == 0 +*/ +); + + /* + * Never split images whose depth + * is less than 15. + */ + + if (split == 1 && (nxagentSplitTrap == 1 || depth < 15)) + { + #ifdef TEST + + if (nxagentSplitTrap == 1 || + nxagentReconnectTrap == 1) + { + fprintf(stderr, "nxagentPutImage: Not splitting with reconnection [%d] trap [%d] " + "depth [%d].\n", nxagentSplitTrap, nxagentReconnectTrap, depth); + } + + #endif + + split = 0; + } + #ifdef TEST + else if (split == 1) + { + fprintf(stderr, "nxagentPutImage: Splitting with reconnection [%d] trap [%d] " + "depth [%d].\n", nxagentSplitTrap, nxagentReconnectTrap, depth); + } + #endif + + #ifdef TEST + + if (split == 1) + { + fprintf(stderr, "nxagentPutImage: Splitting the image with size [%d] " + "link [%d] GLX [%d] Xv [%d].\n", length, nxagentOption(LinkType), + nxagentGlxTrap, nxagentXvTrap); + } + else if (nxagentOption(LinkType) != LINK_TYPE_NONE) + { + fprintf(stderr, "nxagentPutImage: Not splitting the image with size [%d] " + "link [%d] GLX [%d] Xv [%d].\n", length, nxagentOption(LinkType), + nxagentGlxTrap, nxagentXvTrap); + } + + #endif + + /* + * If the image was originated by a GLX + * or Xvideo request, temporarily disable + * the use of the cache. + */ + + if (nxagentOption(LinkType) != LINK_TYPE_NONE && + (nxagentGlxTrap == 1 || nxagentXvTrap == 1)) + { + #ifdef TEST + fprintf(stderr, "nxagentPutImage: Disabling the use of the cache with GLX or Xvideo.\n"); + #endif + + NXSetCacheParameters(nxagentDisplay, 0, 1, 0, 0); + + cache = 0; + } + + /* + * Enclose the next messages in a split + * sequence. The proxy will tell us if + * the split took place. + */ + + if (split == 1) + { + /* + * If the drawable is already being split, + * expand the region. Currently drawables + * can't have more than a single split + * region. + */ + + if (nxagentSplitResource(pDrawable) != NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentPutImage: WARNING! Expanding the region with drawable at [%p] streaming.\n", + (void *) pDrawable); + #endif +/* +FIXME: Should probably intersect the region with + the region being split to also invalidate + the commits. +*/ + nxagentMarkCorruptedRegion(pDrawable, pRegion); + + goto nxagentPutImageEnd; + } + else + { + /* + * Assign a new resource to the drawable. + * Will also assign the GC to use for the + * operation. + */ + + resource = nxagentCreateSplit(pDrawable, &pGC); + + #ifdef TEST + fprintf(stderr, "nxagentPutImage: Resource [%d] assigned to drawable at [%p].\n", + resource, (void *) pDrawable); + #endif + } + + NXStartSplit(nxagentDisplay, resource, NXSplitModeDefault); + } + + nxagentRealizeImage(pDrawable, pGC, depth, dstX, dstY, + dstWidth, dstHeight, leftPad, format, data); + + if (split == 1) + { + NXEndSplit(nxagentDisplay, resource); + + /* + * Now we need to check if all the messages went + * straight through the output stream or any of + * them required a split. If no split will take + * place, we will remove the association with the + * drawable and release the resource at the time + * we will handle the no-split event. + */ + + split = nxagentWaitSplitEvent(resource); + + if (split == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentPutImage: Marking corrupted region [%d,%d,%d,%d] for drawable at [%p].\n", + pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, + pRegion -> extents.y2, (void *) pDrawable); + #endif + + /* + * Marking the corrupted region we will check + * if the region intersects the split region, + * therefore the split region must be added + * later. + */ + + nxagentMarkCorruptedRegion(pDrawable, pRegion); + + /* + * Assign the region to the drawable. + */ + + nxagentRegionSplit(pDrawable, pRegion); + + pRegion = NullRegion; + } + } + + /* + * The split value could be changed by a + * no-split event in the block above, so + * here we have to check the value again. + */ + + if (split == 0) + { + if (nxagentDrawableStatus(pDrawable) == NotSynchronized) + { + /* + * We just covered the drawable with + * a solid image. We can consider the + * overlapping region as synchronized. + */ + + #ifdef TEST + fprintf(stderr, "nxagentPutImage: Marking synchronized region [%d,%d,%d,%d] for drawable at [%p].\n", + pRegion -> extents.x1, pRegion -> extents.y1, pRegion -> extents.x2, + pRegion -> extents.y2, (void *) pDrawable); + #endif + + nxagentUnmarkCorruptedRegion(pDrawable, pRegion); + } + } + +nxagentPutImageEnd: + + /* + * Check if we disabled caching. + */ + + if (cache == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentPutImage: Reenabling the use of the cache.\n"); + #endif + + NXSetCacheParameters(nxagentDisplay, 1, 1, 1, 1); + } + + if (pRegion != NullRegion) + { + nxagentFreeRegion(pDrawable, pRegion); + } +} + +void nxagentRealizeImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, + int format, char *data) +{ + int length; + + int bytesPerLine; + int numSubImages; + int totalHeight; + + /* + * NXPutPackedImage is longer than PutPackedImage + * so that we subtract the bigger one to be sure. + */ + + const int subSize = (MAX_REQUEST_SIZE << 2) - sizeof(xNXPutPackedImageReq); + + Visual *pVisual = NULL; + + RegionPtr clipRegion = NullRegion; + + XImage *image = NULL; + + + if (NXDisplayError(nxagentDisplay) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentRealizeImage: Returning on display error.\n"); + #endif + + goto nxagentRealizeImageEnd; + } + + /* + * Get the visual according to the + * drawable and depth. + */ + + pVisual = nxagentImageVisual(pDrawable, depth); + + if (pVisual == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentRealizeImage: WARNING! Visual not found. Using default visual.\n"); + #endif + + pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual; + } + + /* + * Get bytes per line according to format. + */ + + bytesPerLine = nxagentImagePad(w, format, leftPad, depth); + + if (nxagentOption(Shadow) == 1 && format == ZPixmap && + (nxagentOption(XRatio) != DONT_SCALE || + nxagentOption(YRatio) != DONT_SCALE) && + pDrawable == (DrawablePtr) nxagentShadowPixmapPtr) + { + int scaledx; + int scaledy; + + image = XCreateImage(nxagentDisplay, pVisual, depth, ZPixmap, + 0, data, w, h, BitmapPad(nxagentDisplay), bytesPerLine); + + if (image != NULL) + { + image -> byte_order = IMAGE_BYTE_ORDER; + + image -> bitmap_bit_order = BITMAP_BIT_ORDER; + + nxagentScaleImage(x, y, nxagentOption(XRatio), nxagentOption(YRatio), + &image, &scaledx, &scaledy); + + x = scaledx; + y = scaledy; + + w = image -> width; + h = image -> height; + + data = image -> data; + + /* + * Width of image has changed. + */ + + bytesPerLine = nxagentImagePad(w, format, leftPad, depth); + } + #ifdef WARNING + else + { + fprintf(stderr, "nxagentRealizeImage: Failed to create XImage for scaling.\n"); + } + #endif + } + + if (w == 0 || h == 0) + { + goto nxagentRealizeImageEnd; + } + + totalHeight = h; + + length = bytesPerLine * h; + + h = (subSize < length ? subSize : length) / bytesPerLine; + + numSubImages = totalHeight / h + 1; + + while (numSubImages > 0) + { + if (pDrawable -> type == DRAWABLE_WINDOW) + { + clipRegion = nxagentCreateRegion(pDrawable, pGC, x, y, w, h); + } + + if (clipRegion == NullRegion || RegionNil(clipRegion) == 0) + { + nxagentPutSubImage(pDrawable, pGC, depth, x, y, w, h, + leftPad, format, data, pVisual); + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentRealizeImage: Skipping the put sub image with geometry " + "[%d,%d,%d,%d] on hidden window at [%p].\n", x, y, w, h, (void *) pDrawable); + } + #endif + + if (clipRegion != NullRegion) + { + nxagentFreeRegion(pDrawable, clipRegion); + } + + y += h; + + data += h * bytesPerLine; + + if (--numSubImages == 1) + { + h = totalHeight % h; + + if (h == 0) + { + break; + } + } + } + +nxagentRealizeImageEnd: + + if (image != NULL) + { + XDestroyImage(image); + } +} + +void nxagentPutSubImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *data, Visual *pVisual) +{ + NXPackedImage *packedImage = NULL; + XImage *plainImage = NULL; + unsigned char *packedChecksum = NULL; + + unsigned int packMethod = nxagentPackMethod; + unsigned int packQuality = nxagentPackQuality; + + ClientPtr client; + + int lossless = 0; + int clean = 0; + int pack = 0; + + /* + * XCreateImage is the place where the leftPad should be passed. + * The image data is received from our client unmodified. In + * theory what we would need to do is just creating an appropri- + * ate XImage structure based on the incoming data and let Xlib + * do the rest. Probably we don't have to pass leftPad again in + * the src_x of XPutImage otherwise the src_x would make Xlib + * to take into account the xoffset field twice. Unfortunately + * passing the leftPad doesn't work. + * + * plainImage = XCreateImage(nxagentDisplay, pVisual, + * depth, format, leftPad, data, + * w, h, BitmapPad(nxagentDisplay), + * nxagentImagePad(w, format, leftPad, depth)); + */ + + if ((plainImage = XCreateImage(nxagentDisplay, pVisual, + depth, format, leftPad, data, + w, h, BitmapPad(nxagentDisplay), + nxagentImagePad(w, format, leftPad, depth))) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentPutSubImage: WARNING! Failed to create image.\n"); + #endif + + goto nxagentPutSubImageEnd; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentPutSubImage: Handling image with geometry [%d,%d] depth [%d].\n", + w, h, depth); + + fprintf(stderr, "nxagentPutSubImage: Default pack method is [%d] quality is [%d].\n", + packMethod, packQuality); + #endif + +/* +FIXME: Should use an unpack resource here. +*/ + client = requestingClient; + + if (client == NULL) + { + client = serverClient; + + #ifdef TEST + fprintf(stderr, "nxagentPutSubImage: WARNING! Using the server client with index [%d].\n", + client -> index); + #endif + } + + #ifdef TEST + fprintf(stderr, "nxagentPutSubImage: Server order is [%d] client order is [%d].\n", + nxagentServerOrder(), nxagentClientOrder(client)); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentPutSubImage: Display image order is [%d] bitmap order is [%d].\n", + ImageByteOrder(nxagentDisplay), nxagentBitmapBitOrder(nxagentDisplay)); + #endif + + /* + * We got the image data from the X client or + * from the frame-buffer with our own endianess. + * Byte swap the image data if the display has + * a different endianess than our own. + */ + + if (nxagentImageNormalize(plainImage) != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentPutSubImage: WARNING! Reformatted the image with remote order [%d/%d].\n", + plainImage -> byte_order, plainImage -> bitmap_bit_order); + #endif + } + + #ifdef TEST + fprintf(stderr, "nxagentPutSubImage: Image has visual with RGB color masks [%0lx][%0lx][%0lx].\n", + pVisual -> red_mask, pVisual -> green_mask, pVisual -> blue_mask); + #endif + + /* + * Check if the user requested to pack the + * image but don't pack it if we are not + * connected to a proxy or if the depth is + * less than 15 bpp. + */ + + pack = (nxagentOption(LinkType) != LINK_TYPE_NONE && + packMethod != PACK_NONE && depth > 8 && format == ZPixmap); + + lossless = (packMethod == nxagentPackLossless); + + if (pack == 1 && lossless == 0) + { + /* + * Force the image to be sent as a plain + * bitmap if we don't have any lossless + * encoder available. + */ + + if (w <= IMAGE_PACK_WIDTH || h <= IMAGE_PACK_HEIGHT || + nxagentImageLength(w, h, format, leftPad, depth) <= + IMAGE_PACK_LENGTH || nxagentLosslessTrap == 1) + { + if (nxagentPackLossless == PACK_NONE) + { + #ifdef TEST + fprintf(stderr, "nxagentPutSubImage: Disabling pack with lossless method [%d] " + "trap [%d] size [%d].\n", nxagentPackLossless, nxagentLosslessTrap, + nxagentImageLength(w, h, format, leftPad, depth)); + #endif + + pack = 0; + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentPutSubImage: Lossless encoder with geometry [%d,%d] " + "trap [%d] size [%d].\n", w, h, nxagentLosslessTrap, + nxagentImageLength(w, h, format, leftPad, depth)); + #endif + + packMethod = nxagentPackLossless; + + lossless = 1; + } + } + } + + /* + * Do we still want to pack the image? + */ + + if (pack == 1) + { + /* + * Set the geometry and alpha channel + * to be used for the unpacked image. + */ + + if (nxagentUnpackVisualId[client -> index] != pVisual -> visualid) + { + nxagentUnpackVisualId[client -> index] = pVisual -> visualid; + + #ifdef DEBUG + fprintf(stderr, "nxagentPutSubImage: Sending new geometry for client [%d].\n", + client -> index); + #endif + + NXSetUnpackGeometry(nxagentDisplay, client -> index, pVisual); + } + + /* + * Check if the image is supposed to carry + * the alpha data in the fourth byte and, + * if so, send the alpha channel using the + * specific encoding. + */ + + if (plainImage -> depth == 32) + { + nxagentSetUnpackAlpha(pDrawable, plainImage, client); + } + + /* + * If the image doesn't come from the XVideo or the + * GLX extension try to locate it in the cache. The + * case of the lossless trap is also special, as we + * want to eventually encode the image again using + * a lossless compression. + */ +/* +FIXME: Should try to locate the image anyway, if the lossless + trap is set, and if the image was encoded by a lossy + compressor, roll back the changes and encode the image + again using the preferred method. +*/ + if (nxagentNeedCache(plainImage, packMethod) && + nxagentGlxTrap == 0 && nxagentXvTrap == 0 && + nxagentLosslessTrap == 0 && NXImageCacheSize > 0) + { + /* + * Be sure that the padding bits are + * cleaned before calculating the MD5 + * checksum. + */ +/* +FIXME: There should be a callback registered by the agent that + provides a statistics report, in text format, telling + for example how many images were searched in the cache, + how many were found, how many drawables are to be synch- + ronized, etc. This statistics report would be included + by the proxy in its stat output. +*/ + clean = 1; + + NXCleanImage(plainImage); + + /* + * Will return a pointer to the image and checksum + * taken from the cache, if found. If the image is + * not found, the function returns a null image and + * a pointer to the calculated checksum. It is up + * to the application to free the memory. We will + * use the checksum to add the image in the cache. + */ + + packedImage = NXCacheFindImage(plainImage, &packMethod, &packedChecksum); + + nxagentImageStatistics.partialLookups++; + nxagentImageStatistics.totalLookups++; + + if (packedImage != NULL) + { + #ifdef DEBUG + fprintf(stderr, "nxagentPutSubImage: Matched image of geometry [%d,%d] data size [%d] in cache.\n", + w, h, packedImage -> xoffset); + #endif + + NXPutPackedImage(nxagentDisplay, client -> index, nxagentDrawable(pDrawable), + nxagentGC(pGC), packedImage, packMethod, depth, + 0, 0, x, y, w, h); + + nxagentImageStatistics.partialMatches++; + nxagentImageStatistics.totalMatches++; + + packedChecksum = NULL; + packedImage = NULL; + + goto nxagentPutSubImageEnd; + } + #ifdef DEBUG + else + { + fprintf(stderr, "nxagentPutSubImage: WARNING! Missed image of geometry [%d,%d] in cache.\n", + w, h); + } + #endif + } + + /* + * If a specific encoder was not mandated, + * try to guess if a lossless encoder will + * compress better. + */ + + if (lossless == 0 && nxagentOption(Adaptive) == 1) + { + int ratio = nxagentUniquePixels(plainImage); + + if (ratio <= IMAGE_UNIQUE_RATIO) + { + #ifdef TEST + fprintf(stderr, "nxagentPutSubImage: Lossless encoder with geometry [%d,%d] ratio [%d%%].\n", + w, h, ratio); + #endif + + packMethod = nxagentPackLossless; + + lossless = 1; + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentPutSubImage: Default encoder with geometry [%d,%d] ratio [%d%%].\n", + w, h, ratio); + } + #endif + } + + /* + * Encode the image using the selected + * pack method. + */ + + if (packMethod == PACK_RLE_16M_COLORS || + packMethod == PACK_RGB_16M_COLORS || + packMethod == PACK_BITMAP_16M_COLORS) + { + /* + * Cleanup the image if we didn't do that yet. + * We assume that the JPEG and PNG compression + * methods will actually ignore the padding + * bytes. In other words, bitmap images prod- + * ucing the same visual output should produce + * compressed images that are bitwise the same + * regardless the padding bits. + */ + + if (clean == 0) + { + if (nxagentNeedClean(plainImage, packMethod) == 1) + { + clean = 1; + + NXCleanImage(plainImage); + } + } + + switch (packMethod) + { + /* + * If nothing is done by the bitmap encoder, + * it saves an allocation and a memory copy + * by setting the data field of the packed + * image to the original data. We need to + * check this at the time we will free the + * packed image. + */ + + case PACK_BITMAP_16M_COLORS: + { + packedImage = NXEncodeBitmap(plainImage, packMethod, packQuality); + + break; + } + case PACK_RGB_16M_COLORS: + { + packedImage = NXEncodeRgb(plainImage, packMethod, packQuality); + + break; + } + default: + { + packedImage = NXEncodeRle(plainImage, packMethod, packQuality); + + break; + } + } + } + else if (packMethod >= PACK_JPEG_8_COLORS && + packMethod <= PACK_JPEG_16M_COLORS) + { + packedImage = NXEncodeJpeg(plainImage, packMethod, packQuality); + } + else if (packMethod >= PACK_PNG_8_COLORS && + packMethod <= PACK_PNG_16M_COLORS) + { + packedImage = NXEncodePng(plainImage, packMethod, packQuality); + } + else if (packMethod != PACK_NONE) + { + #ifdef WARNING + fprintf(stderr, "nxagentPutSubImage: WARNING! Ignoring deprecated pack method [%d].\n", + packMethod); + #endif + + packMethod = PACK_NONE; + } + } + + /* + * If we didn't produce a valid packed + * image, send the image as a X bitmap. + */ + + if (packedImage != NULL) + { + nxagentImageStatistics.partialEncoded++; + nxagentImageStatistics.totalEncoded++; + + #ifdef DEBUG + fprintf(stderr, "nxagentPutSubImage: Using packed image with method [%d] quality [%d] " + "geometry [%d,%d] data size [%d].\n", packMethod, packQuality, + w, h, packedImage -> xoffset); + #endif + + NXPutPackedImage(nxagentDisplay, client -> index, nxagentDrawable(pDrawable), + nxagentGC(pGC), packedImage, packMethod, depth, + 0, 0, x, y, w, h); + + /* + * Add the image only if we have a valid + * checksum. This is the case only if we + * originally tried to find the image in + * cache. + */ + + if (NXImageCacheSize > 0 && packedChecksum != NULL) + { + #ifdef DEBUG + fprintf(stderr, "nxagentPutSubImage: Adding image with geometry [%d,%d] data size [%d] " + "to the cache.\n", w, h, packedImage -> xoffset); + #endif + + /* + * Check if both the plain and the packed + * image point to the same data. In this + * case we need a copy. + */ + + if (packedImage -> data == plainImage -> data && + nxagentImageCopy(plainImage, packedImage) == NULL) + { + goto nxagentPutSubImageEnd; + } + + NXCacheAddImage(packedImage, packMethod, packedChecksum); + + nxagentImageStatistics.partialAdded++; + nxagentImageStatistics.totalAdded++; + + packedChecksum = NULL; + packedImage = NULL; + } + } + else + { + /* + * Clean the image to help the proxy to match + * the checksum in its cache. Do that only if + * the differential compression is enabled and + * if the image is not supposed to carry the + * alpha data in the fourth byte of the pixel. + */ +/* +FIXME: If we failed to encode the image by any of the available + methods, for example if we couldn't allocate memory, we + may need to ripristinate the alpha channel, that in the + meanwhile was sent in the unpack alpha message. This can + be done here, if the clean flag is true and we are going + to send a plain image. +*/ + if (clean == 0) + { + clean = (nxagentOption(LinkType) != LINK_TYPE_NONE && + nxagentOption(LinkType) != LINK_TYPE_LAN && depth != 32); + + if (clean == 1) + { + #ifdef DEBUG + fprintf(stderr, "nxagentPutSubImage: Cleaning the image with link type [%d] and depth [%d].\n", + nxagentOption(LinkType), depth); + #endif + + NXCleanImage(plainImage); + } + #ifdef DEBUG + else + { + fprintf(stderr, "nxagentPutSubImage: Not cleaning the image with link type [%d] and depth [%d].\n", + nxagentOption(LinkType), depth); + } + #endif + } + + #ifdef DEBUG + fprintf(stderr, "nxagentPutSubImage: Calling XPutImage with geometry [%d,%d] and data size [%d].\n", + w, h, plainImage -> bytes_per_line * plainImage -> height); + #endif + + /* + * Passing the leftPad value in src_x doesn't work. + * + * XPutImage(nxagentDisplay, nxagentDrawable(pDrawable), + * nxagentGC(pGC), plainImage, leftPad, 0, x, y, w, h); + */ + + XPutImage(nxagentDisplay, nxagentDrawable(pDrawable), + nxagentGC(pGC), plainImage, 0, 0, x, y, w, h); + } + +nxagentPutSubImageEnd: + + #ifdef TEST + fprintf(stderr, "nxagentPutSubImage: Performed [%.0f] lookups in the cache with [%.0f] matches.\n", + nxagentImageStatistics.totalLookups, nxagentImageStatistics.totalMatches); + + fprintf(stderr, "nxagentPutSubImage: Encoded [%.0f] images with [%.0f] added to the cache.\n", + nxagentImageStatistics.totalEncoded, nxagentImageStatistics.totalAdded); + #endif + + if (packedChecksum != NULL) + { + free(packedChecksum); + } + + if (packedImage != NULL) + { + if (packedImage -> data != NULL && + packedImage -> data != plainImage -> data) + { + free(packedImage -> data); + } + + free(packedImage); + } + + free(plainImage); +} + +void nxagentGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *data) +{ + #ifdef TEST + fprintf(stderr, "nxagentGetImage: Called with drawable at [%p] geometry [%d,%d,%d,%d].\n", + (void *) pDrawable, x, y, w, h); + + fprintf(stderr, "nxagentGetImage: Format is [%d] plane mask is [%lx].\n", + format, planeMask); + #endif + + if ((pDrawable)->type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "nxagentGetImage: Going to get image from virtual pixmap at [%p].\n", + (void *) nxagentVirtualDrawable(pDrawable)); + #endif + + fbGetImage(nxagentVirtualDrawable(pDrawable), x, y, w, h, format, planeMask, data); + } + else + { + fbGetImage(pDrawable, x, y, w, h, format, planeMask, data); + } +} + +/* + * We have to reset the visual cache before + * connecting to another display, so that a + * new unpack geometry can be communicated + * to the new proxy. + */ + +void nxagentResetVisualCache() +{ + int i; + + for (i = 0; i < MAX_CONNECTIONS; i++) + { + nxagentUnpackVisualId[i] = None; + } +} + +void nxagentResetAlphaCache() +{ + int i; + + for (i = 0; i < MAX_CONNECTIONS; i++) + { + if (nxagentUnpackAlpha[i]) + { + free(nxagentUnpackAlpha[i] -> data); + + free(nxagentUnpackAlpha[i]); + + nxagentUnpackAlpha[i] = NULL; + } + } +} + +int nxagentScaleImage(int x, int y, unsigned xRatio, unsigned yRatio, + XImage **pImage, int *scaledx, int *scaledy) +{ + int x1; + int x2; + int y1; + int y2; + + int xx1; + int xx2; + int yy1; + int yy2; + + int newWidth; + int newHeight; + + int i; + int j; + int k; + int l; + + unsigned long val; + + XImage *newImage; + XImage *image = *pImage; + + #ifdef FAST_GET_PUT_PIXEL + + register char *srcPixel; + register char *dstPixel; + + int i; + + #endif + + if (image == NULL) + { + return 0; + } + + x1 = (xRatio * x) >> PRECISION; + x2 = (xRatio * (x + image -> width)) >> PRECISION; + + y1 = (yRatio * y) >> PRECISION; + y2 = (yRatio * (y + image -> height)) >> PRECISION; + + newWidth = x2 - x1; + newHeight = y2 - y1; + + newImage = XCreateImage(nxagentDisplay, NULL, image -> depth, image -> format, 0, NULL, + newWidth, newHeight, BitmapPad(nxagentDisplay), + PixmapBytePad(newWidth, image -> depth)); + + if (newImage == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentScaleImage: PANIC! Failed to create the target image.\n"); + #endif + + return 0; + } + + newImage -> red_mask = image -> red_mask; + newImage -> green_mask = image -> green_mask; + newImage -> blue_mask = image -> blue_mask; + + newImage -> byte_order = IMAGE_BYTE_ORDER; + newImage -> bitmap_bit_order = BITMAP_BIT_ORDER; + + newImage -> data = Xmalloc(newImage -> bytes_per_line * newHeight); + + if (newImage -> data == NULL) + { + free(newImage); + + #ifdef PANIC + fprintf(stderr, "nxagentScaleImage: PANIC! Failed to create the target image data.\n"); + #endif + + return 0; + } + + newImage -> width = newWidth; + newImage -> height = newHeight; + + for (j = y; j < y + image -> height; j++) + { + yy1 = (yRatio * j) >> PRECISION; + yy2 = (yRatio * (j + 1)) >> PRECISION; + + for (i = x; i < x + image -> width; i++) + { + #ifndef FAST_GET_PUT_PIXEL + + val = XGetPixel(image, i - x, j - y); + + #else + + srcPixel = &image -> data[(j * image -> bytes_per_line) + + ((i * image -> bits_per_pixel) >> 3)]; + + dstPixel = (char *) &val; + + val = 0; + + for (i = (image -> bits_per_pixel + 7) >> 3; --i >= 0; ) + { + *dstPixel++ = *srcPixel++; + } + + #endif + + xx1 = (xRatio * i) >> PRECISION; + xx2 = (xRatio * (i + 1)) >> PRECISION; + + for (l = yy1; l < yy2; l++) + { + for (k = xx1; k < xx2; k++) + { + #ifndef FAST_GET_PUT_PIXEL + + XPutPixel(newImage, k - x1, l - y1, val); + + #else + + dstPixel = &newImage -> data[((l - y1) * newImage -> bytes_per_line) + + (((k - x1) * newImage -> bits_per_pixel) >> 3)]; + + srcPixel = (char *) &val; + + for (i = (newImage -> bits_per_pixel + 7) >> 3; --i >= 0; ) + { + *dstPixel++ = *srcPixel++; + } + + #endif + } + } + } + } + + if (image -> obdata != NULL) + { + free((char *) image -> obdata); + } + + free((char *) image); + + *pImage = newImage; + + *scaledx = x1; + *scaledy = y1; + + return 1; +} + +char *nxagentAllocateImageData(int width, int height, int depth, int *length, int *format) +{ + char *data; + + int leftPad; + + leftPad = 0; + + *format = (depth == 1) ? XYPixmap : ZPixmap; + + *length = nxagentImageLength(width, height, *format, leftPad, depth); + + data = NULL; + + if ((data = malloc(*length)) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentAllocateImageData: WARNING! Failed to allocate [%d] bytes of memory.\n", *length); + #endif + } + + return data; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Image.h b/nx-X11/programs/Xserver/hw/nxagent/Image.h new file mode 100644 index 000000000..771c0dbe1 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Image.h @@ -0,0 +1,116 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Image_H__ +#define __Image_H__ + +/* + * Graphic operations. + */ + +void nxagentPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int dstX, int dstY, int dstWidth, int dstHeight, + int leftPad, int format, char *data); + +void nxagentRealizeImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, + int format, char *data); + +void nxagentPutSubImage(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *data, Visual *pVisual); + +void nxagentGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *data); + +/* + * Pack and split parameters we get + * from the NX transport. + */ + +extern int nxagentPackLossless; +extern int nxagentPackMethod; +extern int nxagentPackQuality; +extern int nxagentSplitThreshold; + +/* + * Set if images can use the alpha + * channel and if the alpha channel + * can be sent in compressed form. + */ + +extern int nxagentAlphaEnabled; +extern int nxagentAlphaCompat; + +/* + * Reset the visual and alpha cache + * before closing the screen or con- + * necting to a different display. + */ + +void nxagentResetVisualCache(void); +void nxagentResetAlphaCache(void); + +/* + * Always use the default visual for the + * image related functions. + */ + +#define nxagentImageVisual(pDrawable, depth) \ + ((depth) == 32 ? &nxagentAlphaVisual : \ + nxagentDefaultVisual(((pDrawable) -> pScreen))) + +/* + * Byte swap the image if the display + * uses a different endianess. + */ + +#define nxagentImageNormalize(image) \ + ((image) -> byte_order != IMAGE_BYTE_ORDER || \ + (image) -> bitmap_bit_order != BITMAP_BIT_ORDER ? \ + nxagentImageReformat((image) -> data, (image) -> bytes_per_line * \ + (image) -> height * ((image) -> format == XYPixmap ? (image) -> depth : 1), \ + ((image) -> format == ZPixmap ? \ + BitsPerPixel((image) -> depth) : 1), \ + (image) -> byte_order) : 0) + +/* + * Other image related functions. + */ + +int nxagentImageLength(int width, int height, int format, int leftPad, int depth); + +int nxagentImagePad(int width, int format, int leftPad, int depth); + +int nxagentImageReformat(char *base, int nbytes, int bpp, int order); + +void nxagentImageStatisticsHandler(char **buffer, int type); + +int nxagentScaleImage(int x, int y, unsigned xRatio, unsigned yRatio, XImage **pImage, int *scaledx, int *scaledy); + +char *nxagentAllocateImageData(int width, int height, int depth, int *length, int *format); + +#endif /* __Image_H__ */ + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Imakefile b/nx-X11/programs/Xserver/hw/nxagent/Imakefile new file mode 100644 index 000000000..a1b059cae --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Imakefile @@ -0,0 +1,270 @@ +#include <Server.tmpl> + + +NULL = + +SUBDIRS = compext \ + $(NULL) + +SRCS = \ + NXwindow.c \ + NXevents.c \ + NXproperty.c \ + NXdixfonts.c \ + NXglyphcurs.c \ + NXdispatch.c \ + NXrender.c \ + NXglyph.c \ + NXpicture.c \ + NXextension.c \ + NXshm.c \ + NXglxext.c \ + NXxvdisp.c \ + NXmiexpose.c \ + NXresource.c \ + NXdamage.c \ + NXmitrap.c \ + Args.c \ + Binder.c \ + BitmapUtils.c \ + Colormap.c \ + Cursor.c \ + Dialog.c \ + Display.c \ + Events.c \ + Font.c \ + GC.c \ + GCOps.c \ + Millis.c \ + Handlers.c \ + Init.c \ + Keyboard.c \ + Keystroke.c \ + Pointer.c \ + Screen.c \ + TestExt.c \ + Visual.c \ + Drawable.c \ + Window.c \ + Pixmap.c \ + Render.c \ + Client.c \ + Rootless.c \ + Extensions.c \ + Options.c \ + Clipboard.c \ + Splash.c \ + Split.c \ + Holder.c \ + Reconnect.c \ + Error.c \ + Atoms.c \ + Trap.c \ + Image.c \ + Composite.c \ + Pixels.c \ + stubs.c \ + xpstubs.c \ + miinitext.c \ + $(NULL) + +OBJS = \ + NXwindow.o \ + NXevents.o \ + NXproperty.o \ + NXdixfonts.o \ + NXglyphcurs.o \ + NXdispatch.o \ + NXrender.o \ + NXglyph.o \ + NXpicture.o \ + NXextension.o \ + NXshm.o \ + NXglxext.o \ + NXxvdisp.o \ + NXmiexpose.o \ + NXresource.o \ + NXdamage.o \ + NXmitrap.o \ + Args.o \ + Binder.o \ + BitmapUtils.o \ + Colormap.o \ + Cursor.o \ + Dialog.o \ + Display.o \ + Events.o \ + Font.o \ + GC.o \ + GCOps.o \ + Millis.o \ + Handlers.o \ + Init.o \ + Keyboard.o \ + Keystroke.o \ + Pointer.o \ + Screen.o \ + TestExt.o \ + Visual.o \ + Drawable.o \ + Window.o \ + Pixmap.o \ + Render.o \ + Client.o \ + Rootless.o \ + Extensions.o \ + Options.o \ + Clipboard.o \ + Splash.o \ + Split.o \ + Holder.o \ + Reconnect.o \ + Error.o \ + Atoms.o \ + Trap.o \ + Image.o \ + Composite.o \ + Pixels.o \ + stubs.o \ + xpstubs.o \ + miinitext.o \ + $(NULL) + +VFBINCLUDES = \ + -I../../fb \ + -I../../mfb \ + -I../../render \ + $(NULL) + +INCLUDES = \ + -I. \ + -I../../../../extras/Mesa/include \ + -I$(XBUILDINCDIR) \ + -I../../mi \ + -I../../include \ + -I../../os \ + -I../../miext/damage \ + -I../../miext/cw \ + -I../../GL/glx \ + -I../../GL/include \ + -I../../../../lib/GL/include \ + -I../../Xext \ + -I$(EXTINCSRC) -I$(XINCLUDESRC) \ + $(VFBINCLUDES) \ + `pkg-config --cflags-only-I libxml-2.0` \ + `pkg-config --cflags-only-I pixman-1` \ + $(NULL) +#ifdef SunArchitecture +INCLUDES = \ + -I. \ + -I../../../../extras/Mesa/include \ + -I$(XBUILDINCDIR) \ + -I/usr/sfw/include \ + -I../../mi \ + -I../../include \ + -I../../os \ + -I../../GL/glx \ + -I../../GL/include \ + -I../../../../lib/GL/include \ + -I../../Xext \ + -I../../miext/damage \ + -I../../miext/cw \ + -I$(EXTINCSRC) -I$(XINCLUDESRC) \ + $(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 libpng` \ + $(NULL) +#else +#ifdef cygwinArchitecture +INCLUDES = \ + -I. -I$(XBUILDINCDIR) \ + -I../../mi \ + -I../../include \ + -I../../os \ + -I../../GL/glx \ + -I../../GL/include \ + -I../../../../lib/GL/include \ + -I../../Xext \ + -I../../miext/damage \ + -I../../miext/cw \ + -I../../../../../nxcomp \ + -I../../../../../nxcompshad \ + -I../../../../extras/Mesa/include \ + -I$(EXTINCSRC) -I$(XINCLUDESRC) \ + $(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 libpng` \ + $(NULL) +#endif +#endif + +### NXAGENT Defines: +# +# NXAGENT_FONTCACHE_SIZE Number of cache slots +# NXAGENT_SHAPE Old shape code +# NXAGENT_GLYPHCACHE +# NXAGENT_GLYPHCACHE_SIZE Slots for glyph cache +# NXAGENT_SHAPE2 New shape code +# NXAGENT_FIXKEYS Force the release of pressed key when loosing focus +# NXAGENT_EXPOSURES Manage expose events +# NXAGENT_CLIPBOARD Enables clipboard cut and paste function between X servers. +# NXAGENT_FONTEXCLUDE Exclude some specific font names (only "-ult1mo" at this moment). +# NXAGENT FULLSCREEN Fullscreen mode +# NXAGENT_RANDR_MODE_PREFIX Use prefixed (i.e., nx_<x>x<y>) RandR modes +# NXAGENT_RANDR_XINERAMA_CLIPPING cut off invisible window parts in xinerama mode (you probably do not want this) + +#if nxVersion +NX_DEFINES = \ + -DNX_VERSION_CURRENT="$(NX_VERSION_CURRENT)" \ + -DNX_VERSION_CURRENT_STRING="\"$(NX_VERSION_CURRENT_STRING)\"" \ + $(NULL) +#endif + +DEFINES = \ + -g $(OS_DEFINES) $(EXT_DEFINES) $(NX_DEFINES) \ + -UXF86VIDMODE -UXFreeXDGA -UXF86MISC -UXF86DRI \ + -DNXAGENT_SERVER \ + -DNXAGENT_CONSTRAINCURSOR \ + -DNXAGENT_FONTCACHE_SIZE=50 \ + -DNXAGENT_GLYPHCACHE -DNXAGENT_GLYPHCACHE_SIZE=50 \ + -DNXAGENT_SHAPE2 \ + -DNXAGENT_FIXKEYS \ + -DNXAGENT_CLIPBOARD \ + -DNXAGENT_EXPOSURES \ + -DNXAGENT_FONTEXCLUDE \ + -DNXAGENT_PACKEDIMAGES \ + -DNXAGENT_VISIBILITY \ + -DNXAGENT_WAKEUP=1000 \ + -DNXAGENT_ONSTART \ + -DNXAGENT_SPLASH \ + -DNXAGENT_ARTSD \ + -DNXAGENT_RANDR_MODE_PREFIX \ + -UNX_DEBUG_INPUT \ + -DRANDR_10_INTERFACE=1 \ + -DRANDR_12_INTERFACE=1 \ + -DRANDR_13_INTERFACE=1 \ + -DRANDR_14_INTERFACE=1 \ + -DRANDR_15_INTERFACE=1 \ + -DPANORAMIX \ + -UDEBUG_TREE \ + $(NULL) + +all:: $(OBJS) + +LinkSourceFile(stubs.c,$(SERVERSRC)/Xi) +LinkSourceFile(xpstubs.c,$(SERVERSRC)/dix) +LinkSourceFile(miinitext.c,$(SERVERSRC)/mi) +SpecialCObjectRule(miinitext,$(ICONFIGFILES), $(_NOOP_)) + +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 new file mode 100644 index 000000000..a35e3d5a8 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Init.c @@ -0,0 +1,581 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include <sys/types.h> +#include <unistd.h> +#include <stdarg.h> + +#include "X.h" +#include "Xproto.h" +#include "screenint.h" +#include "input.h" +#include "misc.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "servermd.h" +#include "mi.h" +#include <X11/fonts/fontstruct.h> +#include "dixfontstr.h" + +#include "Agent.h" +#include "Display.h" +#include "Screen.h" +#include "Pointer.h" +#include "Keyboard.h" +#include "Handlers.h" +#include "Events.h" +#include "Init.h" +#include "Args.h" +#include "Client.h" +#include "Options.h" +#include "Drawable.h" +#include "Pixmaps.h" +#include "GCs.h" +#include "Font.h" +#include "Millis.h" +#include "Error.h" +#include "Keystroke.h" + +#include <nx/NX.h> +#include "compext/Compext.h" +#include "Reconnect.h" +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +#define NXAGENT_VERSION NX_VERSION_CURRENT +#define NXAGENT_VERSION_STRING NX_VERSION_CURRENT_STRING + +/* + * ProcVector array defined in tables.c. + */ + +extern int (*ProcVector[256])(ClientPtr); + +/* + * From the fb code. + */ + +extern int fbGCPrivateIndex; + +/* + * Stubs for the DPMS extension. + */ + +#ifdef DPMSExtension + +void DPMSSet(int level); +int DPMSGet(int *level); +Bool DPMSSupported(void); + +#endif + +/* + * Our error logging function. + */ + +void OsVendorVErrorFFunction(const char *f, va_list args); + +/* + * True if this is a fatal error. + */ + +extern int OsVendorVErrorFFatal; + +/* + * Redirect the error output to a + * different file + */ + +extern void (*OsVendorStartRedirectErrorFProc)(); +extern void (*OsVendorEndRedirectErrorFProc)(); + +extern void SetVendorRelease(int release); + +void OsVendorStartRedirectErrorFFunction(); +void OsVendorEndRedirectErrorFFunction(); + +/* + * Called by InitGlobals() in the + * new X server tree. + */ + + +static void nxagentGrabServerCallback(CallbackListPtr *callbacks, void *data, + void *args); + +void ddxInitGlobals(void) +{ + /* + * Install our error logging function. + */ + + OsVendorVErrorFProc = OsVendorVErrorFFunction; + + OsVendorStartRedirectErrorFProc = OsVendorStartRedirectErrorFFunction; + OsVendorEndRedirectErrorFProc = OsVendorEndRedirectErrorFFunction; +} + +/* + * Set if the remote display supports + * backing store. + */ +/* +FIXME: These, if not removed, should at least + be moved to Display.h and Display.c. +*/ +int nxagentBackingStore; +int nxagentSaveUnder; + +/* + * This is true at startup and set to the value of + * nxagentFullGeneration at the end of InitInput. + * + * InitOutput + * nxagentOpenDisplay (if nxagentDoFullGeneration) + * nxagentCloseDisplay (if (nxagentDoFullGeneration && nxagentDisplay)) + * nxagentFree* + * nxagentListRemoteFonts + * AddScreen + * nxagentOpenScreen + * InitInput + */ + +int nxagentDoFullGeneration = 1; + + /* + * 1 if agent running as X2goAgent + * 0 if NX Agent + */ +int nxagentX2go; + +/* + * Checking if agent is x2go agent + */ + +void checkX2goAgent() +{ + extern const char *__progname; + if( strcasecmp(__progname,"x2goagent") == 0) + { + fprintf(stderr, "\nrunning as X2Go Agent\n"); + nxagentX2go=1; + } + else + nxagentX2go=0; +} + + +/* + * Called at X server's initialization. + */ + +void InitOutput(ScreenInfo *screenInfo, int argc, char *argv[]) +{ + char *authority; + int i; + + #ifdef __sun + + char *environment; + + #endif + + /* + * Check if we running as X2Go Agent + */ + checkX2goAgent(); + + /* + * Print our pid and version information. + */ + + if (serverGeneration <= 1) + { + fprintf(stderr, "\nNXAGENT - Version " NXAGENT_VERSION_STRING "\n\n"); + fprintf(stderr, "Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com)\n"); + fprintf(stderr, "Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de>\n"); + fprintf(stderr, "Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>\n"); + fprintf(stderr, "Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de>\n"); + fprintf(stderr, "Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de>\n"); + fprintf(stderr, "Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com)\n"); + fprintf(stderr, "See https://github.com/ArcticaProject/nx-libs for more information.\n\n"); + + fprintf(stderr, "Info: Agent running with pid '%d'.\n", getpid()); + + fprintf(stderr, "Session: Starting session at '%s'.\n", GetTimeAsString()); + saveAgentState("STARTING"); + } + + /* + * Avoid slowness due to buggy_repeat workaround + * in libcairo versions >= 1.10. + */ + + SetVendorRelease(70000000); + + /* + * Init the time count for image rate. + */ + + if (nxagentOption(ImageRateLimit) != 0) + { + fprintf(stderr, "Info: Image rate limit set to %u kB/s.\n", nxagentOption(ImageRateLimit)); + } + + /* + * Unset the LD_LIBRARY_PATH variable in + * Popen() before calling execl() in the + * child process. + */ + + NXUnsetLibraryPath(1); + + if (serverGeneration == 1) + { + AddCallback(&ServerGrabCallback, nxagentGrabServerCallback, NULL); + } + + if (nxagentUserDefinedFontPath == 0) + { + #ifdef TEST + fprintf(stderr, "InitOutput: Calling nxagentVerifyDefaultFontPath.\n"); + #endif + + nxagentVerifyDefaultFontPath(); + } + #ifdef TEST + else + { + fprintf(stderr, "InitOutput: User defined font path. Skipping the check on the fonts dir.\n"); + } + #endif + + if ((authority = getenv("NX_XAUTHORITY"))) + { + #ifdef __sun + + environment = malloc(15 + strlen(authority)); + + sprintf(environment, "XAUTHORITY=%s", authority); + + if (putenv(environment) < 0) + + #else + + if (setenv("XAUTHORITY", authority, True) < 0) + + #endif + + { + fprintf(stderr, "Warning: Couldn't set the XAUTHORITY environment to [%s]\n", + authority); + } + } + + nxagentInitBSPixmapList(); + + /* + * Open the display. We are at the early startup and + * the information we'll get from the remote X server + * will mandate some of the characteristics of the + * session, like the screen depth. Note that this re- + * liance on the remote display at session startup + * should be removed. We should always operate at 32 + * bpp, internally, and do the required translations + * as soon as the graphic operation needs to be real- + * ized on the remote display. + */ + + nxagentOpenDisplay(argc, argv); + +/* +FIXME: These variables, if not removed at all because have probably + become useless, should be moved to Display.h and Display.c. +*/ + nxagentBackingStore = XDoesBackingStore(DefaultScreenOfDisplay(nxagentDisplay)); + + #ifdef TEST + fprintf(stderr, "InitOutput: Remote display backing store support [%d].\n", + nxagentBackingStore); + #endif + + nxagentSaveUnder = XDoesSaveUnders(DefaultScreenOfDisplay(nxagentDisplay)); + + #ifdef TEST + fprintf(stderr, "InitOutput: Remote display save under support [%d].\n", + nxagentSaveUnder); + #endif + + /* + * Initialize the basic screen info. + */ + + nxagentSetScreenInfo(screenInfo); + + /* + * Initialize pixmap formats for this screen. + */ + + nxagentSetPixmapFormats(screenInfo); + + /* + * Get our own privates' index. + */ + + nxagentWindowPrivateIndex = AllocateWindowPrivateIndex(); + nxagentGCPrivateIndex = AllocateGCPrivateIndex(); + RT_NX_GC = CreateNewResourceType(nxagentDestroyNewGCResourceType); +#ifdef HAS_XFONT2 + nxagentFontPrivateIndex = xfont2_allocate_font_private_index(); +#else + nxagentFontPrivateIndex = AllocateFontPrivateIndex(); +#endif /* HAS_XFONT2 */ + RT_NX_FONT = CreateNewResourceType(nxagentDestroyNewFontResourceType); + nxagentClientPrivateIndex = AllocateClientPrivateIndex(); + nxagentPixmapPrivateIndex = AllocatePixmapPrivateIndex(); + RT_NX_PIXMAP = CreateNewResourceType(nxagentDestroyNewPixmapResourceType); + + RT_NX_CORR_BACKGROUND = CreateNewResourceType(nxagentDestroyCorruptedBackgroundResource); + RT_NX_CORR_WINDOW = CreateNewResourceType(nxagentDestroyCorruptedWindowResource); + RT_NX_CORR_PIXMAP = CreateNewResourceType(nxagentDestroyCorruptedPixmapResource); + + fbGCPrivateIndex = AllocateGCPrivateIndex(); + + if (nxagentNumScreens == 0) + { + nxagentNumScreens = 1; + } + + for (i = 0; i < nxagentNumScreens; i++) + { + AddScreen(nxagentOpenScreen, argc, argv); + } + + nxagentNumScreens = screenInfo->numScreens; + + /* + * Initialize the GCs used by the synchro- + * nization put images. We do it here beca- + * use we use the nxagentDefaultScreen. + */ + + nxagentAllocateGraphicContexts(); + + nxagentDoFullGeneration = nxagentFullGeneration; + + /* + * Use a solid black root window + * background. + */ + + blackRoot = TRUE; + + nxagentInitKeystrokes(False); +} + +void +nxagentNotifyConnection(int fd, int ready, void *data) +{ + nxagentDispatchEvents(NULL); +} + +void InitInput(argc, argv) + int argc; + char *argv[]; +{ + void *ptr, *kbd; + + ptr = AddInputDevice(nxagentPointerProc, True); + kbd = AddInputDevice(nxagentKeyboardProc, True); + + RegisterPointerDevice(ptr); + RegisterKeyboardDevice(kbd); + + mieqInit(kbd, ptr); + + /* + * Add the display descriptor to the + * set of descriptors awaited by the + * dispatcher. + */ + + nxagentAddXConnection(); + + if (nxagentOption(Shadow)) + { + RegisterBlockAndWakeupHandlers(nxagentShadowBlockHandler, nxagentShadowWakeupHandler, NULL); + } + else + { + RegisterBlockAndWakeupHandlers(nxagentBlockHandler, nxagentWakeupHandler, NULL); + } + + /* + * We let the proxy flush the link on our behalf + * after having opened the display. We are now + * entering the dispatcher. From now on we'll + * flush the proxy link explicitly. + */ + + #ifdef TEST + fprintf(stderr, "InitInput: Setting the NX flush policy to deferred.\n"); + #endif + + NXSetDisplayPolicy(nxagentDisplay, NXPolicyDeferred); +} + +/* + * DDX specific abort routine. This is called + * by AbortServer() that, in turn, is called + * by FatalError(). + */ + +void AbortDDX() +{ + nxagentDoFullGeneration = True; + + nxagentCloseDisplay(); + + /* + * Do the required finalization if we + * are not going through the normal + * X server shutdown. + */ + + if ((dispatchException & DE_TERMINATE) == 0) + { + nxagentAbortDisplay(); + } +} + +/* + * Called by GiveUp(). + */ + +void ddxGiveUp() +{ + AbortDDX(); +} + +void ddxBeforeReset(void) +{ +} + +void OsVendorInit() +{ + return; +} + +void OsVendorFatalError() +{ + /* + * Let the session terminate gracely + * from an user's standpoint. + */ + + fprintf(stderr, "Session: Aborting session at '%s'.\n", GetTimeAsString()); + + fprintf(stderr, "Session: Session aborted at '%s'.\n", GetTimeAsString()); +} + +void OsVendorVErrorFFunction(const char *f, va_list args) +{ + if (OsVendorVErrorFFatal == 0) + { + char buffer[1024]; + + vsnprintf(buffer, sizeof(buffer), f, args); + + nxagentStartRedirectToClientsLog(); + + fprintf(stderr, "%s", buffer); + + nxagentEndRedirectToClientsLog(); + } + else + { + LogVWrite(-1, f, args); + } +} + +void OsVendorStartRedirectErrorFFunction() +{ + nxagentStartRedirectToClientsLog(); +} + +void OsVendorEndRedirectErrorFFunction() +{ + nxagentEndRedirectToClientsLog(); +} + +ServerGrabInfoRec nxagentGrabServerInfo; + +static void nxagentGrabServerCallback(CallbackListPtr *callbacks, void *data, + void *args) +{ + ServerGrabInfoRec *grab = (ServerGrabInfoRec*)args; + + nxagentGrabServerInfo.client = grab->client; + nxagentGrabServerInfo.grabstate = grab->grabstate; +} + +#ifdef DPMSExtension + +void DPMSSet(int level) +{ +} + +int DPMSGet(int *level) +{ + return -1; +} + +Bool DPMSSupported(void) +{ + return 1; +} + +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/Init.h b/nx-X11/programs/Xserver/hw/nxagent/Init.h new file mode 100644 index 000000000..34a17067f --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Init.h @@ -0,0 +1,54 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Init_H__ +#define __Init_H__ + +extern int nxagentDoFullGeneration; + +extern int nxagentBackingStore; +extern int nxagentSaveUnder; + +extern int nxagentX2go; + +extern ServerGrabInfoRec nxagentGrabServerInfo; + +void nxagentNotifyConnection(int fd, int ready, void *data); + +#endif /* __Init_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c new file mode 100644 index 000000000..02b60bef4 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.c @@ -0,0 +1,1930 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include "X.h" +#include "Xproto.h" +#include "keysym.h" +#include "screenint.h" +#include "inputstr.h" +#include "misc.h" +#include "scrnintstr.h" +#include "servermd.h" +#include "dixstruct.h" +#include "extnsionst.h" + +#include "Agent.h" +#include "Display.h" +#include "Screen.h" +#include "Keyboard.h" +#include "Events.h" +#include "Options.h" +#include "Error.h" + +#include "compext/Compext.h" + +#include <nx/Shadow.h> + +#ifdef XKB + +#include "globals.h" +#include "property.h" +#include "Init.h" + +#include <nx-X11/extensions/XKB.h> + +/* + we need the client side header here, xkbsrv.h will not work because + server and libX11 have different struct sizes on + 64bit. Interestingly upstream xnest does not take care of this. +*/ +#include <nx-X11/extensions/XKBsrv.h> +#include <nx-X11/extensions/XKBconfig.h> + +#include "Xatom.h" + +#include <errno.h> + +static int nxagentXkbGetNames(char **rules, char **model, char **layout, + char **variant, char **options); + +static void nxagentKeycodeConversionSetup(void); + +#endif /* XKB */ + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef WATCH + +#ifdef WATCH +#include "unistd.h" +#endif + +/* + * Unfortunately we cannot just include XKBlib.h. + * It conflicts with the server side definitions + * of the same symbols. This is more a X problem + * than our. + */ + +#ifdef XKB + +extern Bool XkbQueryExtension( +#if NeedFunctionPrototypes + Display * /* dpy */, + int * /* opcodeReturn */, + int * /* eventBaseReturn */, + int * /* errorBaseReturn */, + int * /* majorRtrn */, + int * /* minorRtrn */ +#endif +); + +extern XkbDescPtr XkbGetKeyboard( +#if NeedFunctionPrototypes + Display * /* dpy */, + unsigned int /* which */, + unsigned int /* deviceSpec */ +#endif +); + +extern Status XkbGetControls( +#if NeedFunctionPrototypes + Display * /* dpy */, + unsigned long /* which */, + XkbDescPtr /* desc */ +#endif +); + +#ifndef XKB_BASE_DIRECTORY +#define XKB_BASE_DIRECTORY "/usr/share/X11/xkb" +#endif +#ifndef XKB_ALTERNATE_BASE_DIRECTORY +#define XKB_ALTERNATE_BASE_DIRECTORY "/usr/X11R6/lib/X11/xkb" +#endif +#ifndef XKB_CONFIG_FILE_NX +#define XKB_CONFIG_FILE_NX "/etc/nxagent/nxagent.keyboard" +#endif +#ifndef XKB_CONFIG_FILE_X2GO +#define XKB_CONFIG_FILE_X2GO "/etc/x2go/x2goagent.keyboard" +#endif +#ifndef XKB_DFLT_RULES_FILE +#define XKB_DFLT_RULES_FILE "xfree86" +#endif +#ifndef XKB_ALTS_RULES_FILE +#define XKB_ALTS_RULES_FILE "xorg" +#endif +#ifndef XKB_DFLT_KB_LAYOUT +#define XKB_DFLT_KB_LAYOUT "us" +#endif +#ifndef XKB_DFLT_KB_MODEL +#define XKB_DFLT_KB_MODEL "pc102" +#endif +#ifndef XKB_DFLT_KB_VARIANT +#define XKB_DFLT_KB_VARIANT NULL +#endif +#ifndef XKB_DFLT_KB_OPTIONS +#define XKB_DFLT_KB_OPTIONS NULL +#endif + +extern int XkbDfltRepeatDelay; +extern int XkbDfltRepeatInterval; + +#endif /* XKB */ + +/* + * Save the values queried from X server. + */ + +XkbAgentInfoRec nxagentXkbInfo = { -1, -1, -1, -1, -1 }; + +/* + * Keyboard status, updated through XKB + * events. + */ + +XkbAgentStateRec nxagentXkbState = { 0, 0, 0, 0, 0 }; + +/* + * Info for disabling/enabling Xkb extension. + */ + +XkbWrapperRec nxagentXkbWrapper; + +extern char *nxagentKeyboard; + +static char *nxagentXkbGetRules(void); + +unsigned int nxagentAltMetaMask; +unsigned int nxagentAltMask; +unsigned int nxagentMetaMask; +unsigned int nxagentCapsMask; +unsigned int nxagentNumlockMask; + +static void nxagentCheckModifierMasks(CARD8, int); + +CARD8 nxagentCapsLockKeycode = 66; +CARD8 nxagentNumLockKeycode = 77; + +static void nxagentCheckRemoteKeycodes(void); + +static CARD8 nxagentConvertedKeycodes[] = +{ + /* evdev pc105*/ + /* 0 */ 0, + /* 1 */ 1, + /* 2 */ 2, + /* 3 */ 3, + /* 4 */ 4, + /* 5 */ 5, + /* 6 */ 6, + /* 7 */ 7, + /* 8 */ 8, + /* 9 */ 9, + /* 10 */ 10, + /* 11 */ 11, + /* 12 */ 12, + /* 13 */ 13, + /* 14 */ 14, + /* 15 */ 15, + /* 16 */ 16, + /* 17 */ 17, + /* 18 */ 18, + /* 19 */ 19, + /* 20 */ 20, + /* 21 */ 21, + /* 22 */ 22, + /* 23 */ 23, + /* 24 */ 24, + /* 25 */ 25, + /* 26 */ 26, + /* 27 */ 27, + /* 28 */ 28, + /* 29 */ 29, + /* 30 */ 30, + /* 31 */ 31, + /* 32 */ 32, + /* 33 */ 33, + /* 34 */ 34, + /* 35 */ 35, + /* 36 */ 36, + /* 37 */ 37, + /* 38 */ 38, + /* 39 */ 39, + /* 40 */ 40, + /* 41 */ 41, + /* 42 */ 42, + /* 43 */ 43, + /* 44 */ 44, + /* 45 */ 45, + /* 46 */ 46, + /* 47 */ 47, + /* 48 */ 48, + /* 49 */ 49, + /* 50 */ 50, + /* 51 */ 51, + /* 52 */ 52, + /* 53 */ 53, + /* 54 */ 54, + /* 55 */ 55, + /* 56 */ 56, + /* 57 */ 57, + /* 58 */ 58, + /* 59 */ 59, + /* 60 */ 60, + /* 61 */ 61, + /* 62 */ 62, + /* 63 */ 63, + /* 64 */ 64, + /* 65 */ 65, + /* 66 */ 66, + /* 67 */ 67, + /* 68 */ 68, + /* 69 */ 69, + /* 70 */ 70, + /* 71 */ 71, + /* 72 */ 72, + /* 73 */ 73, + /* 74 */ 74, + /* 75 */ 75, + /* 76 */ 76, + /* 77 */ 77, + /* 78 */ 78, + /* 79 */ 79, + /* 80 */ 80, + /* 81 */ 81, + /* 82 */ 82, + /* 83 */ 83, + /* 84 */ 84, + /* 85 */ 85, + /* 86 */ 86, + /* 87 */ 87, + /* 88 */ 88, + /* 89 */ 89, + /* 90 */ 90, + /* 91 */ 91, + /* 92 */ 124, + /* 93 */ 93, + /* 94 */ 94, + /* 95 */ 95, + /* 96 */ 96, + /* 97 */ 211, + /* 98 */ 98, + /* 99 */ 99, + /* 100 */ 100, + /* 101 */ 208, + /* 102 */ 102, + /* 103 */ 103, + /* 104 */ 108, + /* 105 */ 109, + /* 106 */ 112, + /* 107 */ 111, + /* 108 */ 113, + /* 109 */ 109, + /* 110 */ 97, + /* 111 */ 98, + /* 112 */ 99, + /* 113 */ 100, + /* 114 */ 102, + /* 115 */ 103, + /* 116 */ 104, + /* 117 */ 105, + /* 118 */ 106, + /* 119 */ 107, + /* 120 */ 120, + /* 121 */ 121, + /* 122 */ 122, + /* 123 */ 123, + /* 124 */ 124, + /* 125 */ 126, + /* 126 */ 126, + /* 127 */ 110, + /* 128 */ 128, + /* 129 */ 129, + /* 130 */ 130, + /* 131 */ 131, + /* 132 */ 133, + /* 133 */ 115, + /* 134 */ 116, + /* 135 */ 117, + /* 136 */ 136, + /* 137 */ 137, + /* 138 */ 138, + /* 139 */ 139, + /* 140 */ 140, + /* 141 */ 141, + /* 142 */ 142, + /* 143 */ 143, + /* 144 */ 144, + /* 145 */ 145, + /* 146 */ 146, + /* 147 */ 147, + /* 148 */ 148, + /* 149 */ 149, + /* 150 */ 150, + /* 151 */ 151, + /* 152 */ 152, + /* 153 */ 153, + /* 154 */ 154, + /* 155 */ 155, + /* 156 */ 156, + /* 157 */ 157, + /* 158 */ 158, + /* 159 */ 159, + /* 160 */ 160, + /* 161 */ 161, + /* 162 */ 162, + /* 163 */ 163, + /* 164 */ 164, + /* 165 */ 165, + /* 166 */ 166, + /* 167 */ 167, + /* 168 */ 168, + /* 169 */ 169, + /* 170 */ 170, + /* 171 */ 171, + /* 172 */ 172, + /* 173 */ 173, + /* 174 */ 174, + /* 175 */ 175, + /* 176 */ 176, + /* 177 */ 177, + /* 178 */ 178, + /* 179 */ 179, + /* 180 */ 180, + /* 181 */ 181, + /* 182 */ 182, + /* 183 */ 183, + /* 184 */ 184, + /* 185 */ 185, + /* 186 */ 186, + /* 187 */ 187, + /* 188 */ 188, + /* 189 */ 189, + /* 190 */ 190, + /* 191 */ 118, + /* 192 */ 119, + /* 193 */ 120, + /* 194 */ 121, + /* 195 */ 122, + /* 196 */ 196, + /* 197 */ 197, + /* 198 */ 198, + /* 199 */ 199, + /* 200 */ 200, + /* 201 */ 201, + /* 202 */ 202, + /* 203 */ 93, + /* 204 */ 125, + /* 205 */ 156, + /* 206 */ 127, + /* 207 */ 128, + /* 208 */ 208, + /* 209 */ 209, + /* 210 */ 210, + /* 211 */ 211, + /* 212 */ 212, + /* 213 */ 213, + /* 214 */ 214, + /* 215 */ 215, + /* 216 */ 216, + /* 217 */ 217, + /* 218 */ 218, + /* 219 */ 219, + /* 220 */ 220, + /* 221 */ 221, + /* 222 */ 222, + /* 223 */ 223, + /* 224 */ 224, + /* 225 */ 225, + /* 226 */ 226, + /* 227 */ 227, + /* 228 */ 228, + /* 229 */ 229, + /* 230 */ 230, + /* 231 */ 231, + /* 232 */ 232, + /* 233 */ 233, + /* 234 */ 234, + /* 235 */ 235, + /* 236 */ 236, + /* 237 */ 237, + /* 238 */ 238, + /* 239 */ 239, + /* 240 */ 240, + /* 241 */ 241, + /* 242 */ 242, + /* 243 */ 243, + /* 244 */ 244, + /* 245 */ 245, + /* 246 */ 246, + /* 247 */ 247, + /* 248 */ 248, + /* 249 */ 249, + /* 250 */ 250, + /* 251 */ 251, + /* 252 */ 252, + /* 253 */ 253, + /* 254 */ 254, + /* 255 */ 255 +}; + +static int nxagentKeycodeConversion = 0; + +CARD8 nxagentConvertKeycode(CARD8 k) +{ + if (nxagentKeycodeConversion != 0) + { + #ifdef DEBUG + if (k != nxagentConvertedKeycodes[k]) + fprintf(stderr, "nxagentConvertKeycode: converting keycode [%d] to [%d]\n", k, nxagentConvertedKeycodes[k]); + #endif + + return nxagentConvertedKeycodes[k]; + } + else + { + return k; + } +} + +static int nxagentSaveKeyboardDeviceData(DeviceIntPtr dev, DeviceIntPtr devBackup); + +static int nxagentRestoreKeyboardDeviceData(DeviceIntPtr devBackup, DeviceIntPtr dev); + +static int nxagentFreeKeyboardDeviceData(DeviceIntPtr dev); + +static void nxagentCheckXkbBaseDirectory(void) +{ + + /* + * Set XkbBaseDirectory global + * variable appropriately. + */ + + #ifdef TEST + fprintf(stderr, "nxagentCheckXkbBaseDirectory: " + "Before calling _NXGetXkbBasePath:\n"); + + fprintf(stderr, "nxagentCheckXkbBaseDirectory: " + "XkbBaseDirectory variable [%s].\n", + XkbBaseDirectory); + #endif + + XkbBaseDirectory = _NXGetXkbBasePath(XkbBaseDirectory); + + #ifdef TEST + fprintf(stderr, "nxagentCheckXkbBaseDirectory: " + "After calling _NXGetXkbBasePath:\n"); + + fprintf(stderr, "nxagentCheckXkbBaseDirectory: " + "XkbBaseDirectory variable [%s].\n", + XkbBaseDirectory); + #endif + + return; +} + +static char *nxagentXkbGetRules() +{ + int ret; + int size, sizeDflt, sizeAlt; + char *path; + struct stat buf; + + #ifdef TEST + fprintf(stderr, "nxagentXkbGetRules: XkbBaseDirectory [%s].\n", + XkbBaseDirectory); + #endif + + sizeDflt = strlen(XKB_DFLT_RULES_FILE); + sizeAlt = strlen(XKB_ALTS_RULES_FILE); + size = strlen(XkbBaseDirectory) + strlen("/rules/"); + size += (sizeDflt > sizeAlt) ? sizeDflt : sizeAlt; + + if ((path = malloc((size + 1) * sizeof(char))) == NULL) + { + FatalError("nxagentXkbGetRules: malloc failed."); + } + + strcpy(path, XkbBaseDirectory); + strcat(path, "/rules/"); + strcat(path, XKB_DFLT_RULES_FILE); + ret = stat(path, &buf); + + if (ret == 0) + { + free(path); + return XKB_DFLT_RULES_FILE; + } + + #ifdef TEST + fprintf(stderr, "nxagentXkbGetRules: WARNING! Failed to stat file [%s]: %s.\n", path, strerror(ret)); + #endif + + strcpy(path, XkbBaseDirectory); + strcat(path, "/rules/"); + strcat(path, XKB_ALTS_RULES_FILE); + ret = stat(path, &buf); + + if (ret == 0) + { + free(path); + return XKB_ALTS_RULES_FILE; + } + + #ifdef WARNING + fprintf(stderr, "nxagentXkbGetRules: WARNING! Failed to stat file [%s]: %s.\n", path, strerror(ret)); + #endif + + free(path); + return XKB_DFLT_RULES_FILE; +} + +void nxagentBell(int volume, DeviceIntPtr pDev, void * ctrl, int cls) +{ + XBell(nxagentDisplay, volume); +} + +void nxagentChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl *ctrl) +{ + #ifdef XKB + + XkbSrvInfoPtr xkbi; + XkbControlsPtr xkbc; + + if (!noXkbExtension) + { + xkbi = pDev -> key -> xkbInfo; + xkbc = xkbi -> desc -> ctrls; + + /* + * We want to prevent agent generating auto-repeated + * keystrokes. Let's intercept any attempt by appli- + * cations to change the default timeouts on the + * nxagent device. + */ + + #ifdef TEST + fprintf(stderr, "nxagentChangeKeyboardControl: Repeat delay was [%d] interval was [%d].\n", + xkbc -> repeat_delay, xkbc -> repeat_interval); + #endif + + xkbc -> repeat_delay = ~ 0; + xkbc -> repeat_interval = ~ 0; + + #ifdef TEST + fprintf(stderr, "nxagentChangeKeyboardControl: Repeat delay is now [%d] interval is now [%d].\n", + xkbc -> repeat_delay, xkbc -> repeat_interval); + #endif + } + + #endif + + /* + * If enabled, propagate the changes to the + * devices attached to the real X server. + */ + + if (nxagentOption(DeviceControl) == True) + { + unsigned long value_mask; + XKeyboardControl values; + int i; + + #ifdef TEST + fprintf(stderr, "nxagentChangeKeyboardControl: WARNING! Propagating changes to keyboard settings.\n"); + #endif + + value_mask = KBKeyClickPercent | + KBBellPercent | + KBBellPitch | + KBBellDuration; + + values.key_click_percent = ctrl->click; + values.bell_percent = ctrl->bell; + values.bell_pitch = ctrl->bell_pitch; + values.bell_duration = ctrl->bell_duration; + + /* + * Don't propagate the auto repeat mode. It is forced to be + * off in the agent server. + * + * value_mask |= KBAutoRepeatMode; + * values.auto_repeat_mode = ctrl->autoRepeat ? + * AutoRepeatModeOn : AutoRepeatModeOff; + */ + + XChangeKeyboardControl(nxagentDisplay, value_mask, &values); + + /* + * At this point, we need to walk through the vector and + * compare it to the current server vector. If there are + * differences, report them. + */ + + value_mask = KBLed | KBLedMode; + + for (i = 1; i <= 32; i++) + { + values.led = i; + values.led_mode = (ctrl->leds & (1 << (i - 1))) ? LedModeOn : LedModeOff; + + XChangeKeyboardControl(nxagentDisplay, value_mask, &values); + } + + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentChangeKeyboardControl: WARNING! Not propagating changes to keyboard settings.\n"); + #endif +} + +int nxagentKeyboardProc(DeviceIntPtr pDev, int onoff) +{ + XModifierKeymap *modifier_keymap; + KeySym *keymap; + int mapWidth; + int min_keycode, max_keycode; + KeySymsRec keySyms; + CARD8 modmap[256]; + int i, j; + XKeyboardState values; + char *model = NULL, *layout = NULL; + int free_model = 0, free_layout = 0; + XkbDescPtr xkb = NULL; + + switch (onoff) + { + case DEVICE_INIT: + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Called for [DEVICE_INIT].\n"); + #endif + + if (NXDisplayError(nxagentDisplay) == 1) + { + return Success; + } + + #ifdef WATCH + + fprintf(stderr, "nxagentKeyboardProc: Watchpoint 9.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +N/A +*/ + + sleep(30); + + #endif + + /* + * Prevent agent from generating auto-repeat keystroke. + * Note that this is working only if XKB is enabled. + * A better solution should account cases where XKB is + * not available. Check also the behaviour of the + * DeviceControl nxagent option. + */ + + XkbDfltRepeatDelay = ~ 0; + XkbDfltRepeatInterval = ~ 0; + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Set repeat delay to [%u] interval to [%u].\n", + XkbDfltRepeatDelay, XkbDfltRepeatInterval); + #endif + + modifier_keymap = XGetModifierMapping(nxagentDisplay); + + if (modifier_keymap == NULL) + { + return -1; + } + + XDisplayKeycodes(nxagentDisplay, &min_keycode, &max_keycode); +#ifdef _XSERVER64 + { + KeySym64 *keymap64; + int i, len; + keymap64 = XGetKeyboardMapping(nxagentDisplay, + min_keycode, + max_keycode - min_keycode + 1, + &mapWidth); + + if (keymap64 == NULL) + { + XFreeModifiermap(modifier_keymap); + + return -1; + } + + len = (max_keycode - min_keycode + 1) * mapWidth; + keymap = (KeySym *)malloc(len * sizeof(KeySym)); + for(i = 0; i < len; ++i) + keymap[i] = keymap64[i]; + XFree(keymap64); + } + +#else /* #ifdef _XSERVER64 */ + + keymap = XGetKeyboardMapping(nxagentDisplay, + min_keycode, + max_keycode - min_keycode + 1, + &mapWidth); + + if (keymap == NULL) + { + XFreeModifiermap(modifier_keymap); + + return -1; + } + +#endif /* #ifdef _XSERVER64 */ + + nxagentAltMetaMask = 0; + nxagentAltMask = 0; + nxagentMetaMask = 0; + nxagentCapsMask = 0; + nxagentNumlockMask = 0; + + for (i = 0; i < 256; i++) + modmap[i] = 0; + for (j = 0; j < 8; j++) + for(i = 0; i < modifier_keymap->max_keypermod; i++) { + CARD8 keycode; + if ((keycode = + modifier_keymap-> + modifiermap[j * modifier_keymap->max_keypermod + i])) + modmap[keycode] |= 1<<j; + + if (keycode > 0) + { + nxagentCheckModifierMasks(keycode, j); + } + } + XFreeModifiermap(modifier_keymap); + + nxagentCheckRemoteKeycodes(); + + keySyms.minKeyCode = min_keycode; + keySyms.maxKeyCode = max_keycode; + keySyms.mapWidth = mapWidth; + keySyms.map = keymap; + +#ifdef XKB + + /* + * First of all the validity + * of XkbBaseDirectory global + * variable is checked. + */ + + nxagentCheckXkbBaseDirectory(); + + if (noXkbExtension) { + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: No XKB extension.\n"); + #endif + +XkbError: + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: XKB error.\n"); + #endif + + XkbFreeKeyboard(xkb, XkbAllComponentsMask, True); + xkb = NULL; + if (free_model) + { + free_model = 0; + free(model); + } + if (free_layout) + { + free_layout = 0; + free(layout); + } +#endif + XGetKeyboardControl(nxagentDisplay, &values); + + memmove((char *) defaultKeyboardControl.autoRepeats, + (char *) values.auto_repeats, sizeof(values.auto_repeats)); + + #ifdef TEST + { + int ret = + #endif + InitKeyboardDeviceStruct((DevicePtr) pDev, &keySyms, modmap, + nxagentBell, nxagentChangeKeyboardControl); + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: InitKeyboardDeviceStruct returns [%d].\n", ret); + } + #endif + +#ifdef XKB + } else { + FILE *file; + XkbConfigRtrnRec config; + + char *nxagentXkbConfigFilePath; + + XkbComponentNamesRec names; + char *rules, *variants, *options; + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Using XKB extension.\n"); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: nxagentKeyboard is [%s].\n", nxagentKeyboard ? nxagentKeyboard : "NULL"); + #endif + + memset(&names, 0, sizeof(XkbComponentNamesRec)); + + rules = nxagentXkbGetRules(); + + if ((nxagentKeyboard != NULL) && (strcmp(nxagentKeyboard, "query") != 0)) + { + for (i = 0; nxagentKeyboard[i] != '/' && nxagentKeyboard[i] != 0; i++); + + if(nxagentKeyboard[i] == 0 || nxagentKeyboard[i + 1] == 0 || i == 0) + { + ErrorF("Warning: Wrong keyboard type: %s.\n", nxagentKeyboard); + + goto XkbError; + } + + free_model = 1; + model = strndup(nxagentKeyboard, i); + + free_layout = 1; + layout = strdup(&nxagentKeyboard[i + 1]); + + /* + * There is no description for pc105 on Solaris. + * Need to revert to the closest approximation. + */ + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Using keyboard model [%s] with layout [%s].\n", + model, layout); + #endif + + #ifdef __sun + + if (strcmp(model, "pc105") == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: WARNING! Keyboard model 'pc105' unsupported on Solaris.\n"); + + fprintf(stderr, "nxagentKeyboardProc: WARNING! Forcing keyboard model to 'pc104'.\n"); + #endif + + strcpy(model, "pc104"); + } + + #endif + } + else + { + layout = XKB_DFLT_KB_LAYOUT; + model = XKB_DFLT_KB_MODEL; + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Using default keyboard: model [%s] layout [%s].\n", + model, layout); + #endif + } + + variants = XKB_DFLT_KB_VARIANT; + options = XKB_DFLT_KB_OPTIONS; + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: XkbInitialMap [%s]\n", XkbInitialMap ? XkbInitialMap : "NULL"); + #endif + + if (XkbInitialMap) { + if ((names.keymap = strchr(XkbInitialMap, '/')) != NULL) + ++names.keymap; + else + names.keymap = XkbInitialMap; + } + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Init XKB extension.\n"); + #endif + + if (XkbQueryExtension(nxagentDisplay, + &nxagentXkbInfo.Opcode, + &nxagentXkbInfo.EventBase, + &nxagentXkbInfo.ErrorBase, + &nxagentXkbInfo.MajorVersion, + &nxagentXkbInfo.MinorVersion) == 0) + { + ErrorF("Unable to initialize XKEYBOARD extension.\n"); + + goto XkbError; + } + + xkb = XkbGetKeyboard(nxagentDisplay, XkbGBN_AllComponentsMask, XkbUseCoreKbd); + + nxagentKeycodeConversionSetup(); + + if (xkb == NULL || xkb->geom == NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: No current keyboard.\n"); + if (xkb == NULL) + { + fprintf(stderr, "nxagentKeyboardProc: xkb is null.\n"); + } + else + { + fprintf(stderr, "nxagentKeyboardProc: xkb->geom is null.\n"); + } + fprintf(stderr, "nxagentKeyboardProc: Going to set rules and init device.\n"); + #endif + #ifdef DEBUG + fprintf(stderr, "nxagentKeyboardProc: Going to set rules and init device: " + "[rules='%s',model='%s',layout='%s',variants='%s',options='%s'].\n", + rules, model, layout, variants, options); + #endif + + XkbSetRulesDflts(rules, model, layout, variants, options); + XkbInitKeyboardDeviceStruct((void *)pDev, &names, &keySyms, modmap, + nxagentBell, nxagentChangeKeyboardControl); + + if (!nxagentKeyboard || strcmp(nxagentKeyboard, "query") == 0) + { + goto XkbError; + } + + goto XkbEnd; + } + + XkbGetControls(nxagentDisplay, XkbAllControlsMask, xkb); + + if (nxagentX2go) + nxagentXkbConfigFilePath = strdup(XKB_CONFIG_FILE_X2GO); + else + nxagentXkbConfigFilePath = strdup(XKB_CONFIG_FILE_NX); + + if (nxagentXkbConfigFilePath == NULL) + { + FatalError("nxagentKeyboardProc: malloc failed."); + } + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: nxagentXkbConfigFilePath [%s].\n", + nxagentXkbConfigFilePath); + #endif + + if ((file = fopen(nxagentXkbConfigFilePath, "r")) != NULL) { + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Going to parse config file.\n"); + #endif + + if (XkbCFParse(file, XkbCFDflts, xkb, &config) == 0) { + ErrorF("Error parsing config file.\n"); + + free(nxagentXkbConfigFilePath); + + fclose(file); + goto XkbError; + } + if (config.rules_file) + rules = config.rules_file; + if (config.model) + { + if (free_model) + { + free_model = 0; + free(model); + } + model = config.model; + } + if (config.layout) + { + if (free_layout) + { + free_layout = 0; + free(layout); + } + layout = config.layout; + } + if (config.variant) + variants = config.variant; + if (config.options) + options = config.options; + + free(nxagentXkbConfigFilePath); + + fclose(file); + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: No config file, going to set rules and init device.\n"); + #endif + #ifdef DEBUG + fprintf(stderr, "nxagentKeyboardProc: Going to set rules and init device: " + "[rules='%s',model='%s',layout='%s',variants='%s',options='%s'].\n", + rules, model, layout, variants, options); + #endif + + XkbSetRulesDflts(rules, model, layout, variants, options); + XkbInitKeyboardDeviceStruct((void *)pDev, &names, &keySyms, modmap, + nxagentBell, nxagentChangeKeyboardControl); + + free(nxagentXkbConfigFilePath); + + if (!nxagentKeyboard || strcmp(nxagentKeyboard, "query") == 0) + { + goto XkbError; + } + + goto XkbEnd; + } + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Going to set rules and init device.\n"); + #endif + #ifdef DEBUG + fprintf(stderr, "nxagentKeyboardProc: Going to set rules and init device: " + "[rules='%s',model='%s',layout='%s',variants='%s',options='%s'].\n", + rules, model, layout, variants, options); + #endif + + XkbSetRulesDflts(rules, model, layout, variants, options); + XkbInitKeyboardDeviceStruct((void *)pDev, &names, &keySyms, modmap, + nxagentBell, nxagentChangeKeyboardControl); + XkbDDXChangeControls((void *)pDev, xkb->ctrls, xkb->ctrls); + +XkbEnd: + + if (nxagentOption(Shadow) == 1 && pDev && pDev->key) + { + NXShadowInitKeymap(&(pDev->key->curKeySyms)); + } + + if (free_model) + { + free_model = 0; + free(model); + } + + if (free_layout) + { + free_layout = 0; + free(layout); + } + + XkbFreeKeyboard(xkb, XkbAllComponentsMask, True); + xkb = NULL; + } +#endif + + #ifdef WATCH + + fprintf(stderr, "nxagentKeyboardProc: Watchpoint 10.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +#1 U 3 2 80320 bits (10 KB) -> 28621 bits (3 KB) -> 26773/1 -> 9540/1 = 2.806:1 +#98 1 256 bits (0 KB) -> 27 bits (0 KB) -> 256/1 -> 27/1 = 9.481:1 +#101 1 32000 bits (4 KB) -> 2940 bits (0 KB) -> 32000/1 -> 2940/1 = 10.884:1 +#119 1 384 bits (0 KB) -> 126 bits (0 KB) -> 384/1 -> 126/1 = 3.048:1 +*/ + + sleep(30); + + #endif + +#ifdef _XSERVER64 + free(keymap); +#else + XFree(keymap); +#endif + break; + case DEVICE_ON: + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Called for [DEVICE_ON].\n"); + #endif + + if (NXDisplayError(nxagentDisplay) == 1) + { + return Success; + } + + #ifdef WATCH + + fprintf(stderr, "nxagentKeyboardProc: Watchpoint 11.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +#117 1 320 bits (0 KB) -> 52 bits (0 KB) -> 320/1 -> 52/1 = 6.154:1 +*/ + + sleep(30); + + #endif + + nxagentEnableKeyboardEvents(); + + break; + + case DEVICE_OFF: + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Called for [DEVICE_OFF].\n"); + #endif + + if (NXDisplayError(nxagentDisplay) == 1) + { + return Success; + } + + nxagentDisableKeyboardEvents(); + + break; + + case DEVICE_CLOSE: + + #ifdef TEST + fprintf(stderr, "nxagentKeyboardProc: Called for [DEVICE_CLOSE].\n"); + #endif + + break; + } + + return Success; +} + +Bool LegalModifier(key, pDev) + unsigned int key; + DevicePtr pDev; +{ + return TRUE; +} + +void nxagentNotifyKeyboardChanges(int oldMinKeycode, int oldMaxKeycode) +{ + #ifdef XKB + + if (!noXkbExtension) + { + DeviceIntPtr dev; + xkbNewKeyboardNotify nkn; + + dev = inputInfo.keyboard; + + memset(&nkn, 0, sizeof(xkbNewKeyboardNotify)); + nkn.deviceID = nkn.oldDeviceID = dev -> id; + nkn.minKeyCode = 8; + nkn.maxKeyCode = 255; + nkn.oldMinKeyCode = oldMinKeycode; + nkn.oldMaxKeyCode = oldMaxKeycode; + nkn.requestMajor = XkbReqCode; + nkn.requestMinor = X_kbGetKbdByName; + nkn.changed = XkbNKN_KeycodesMask; + + XkbSendNewKeyboardNotify(dev, &nkn); + } + else + { + + #endif + + int i; + xEvent event; + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MappingNotify; + event.u.mappingNotify.request = MappingKeyboard; + event.u.mappingNotify.firstKeyCode = inputInfo.keyboard -> key -> curKeySyms.minKeyCode; + event.u.mappingNotify.count = inputInfo.keyboard -> key -> curKeySyms.maxKeyCode - + inputInfo.keyboard -> key -> curKeySyms.minKeyCode; + + /* + * 0 is the server client + */ + + for (i = 1; i < currentMaxClients; i++) + { + if (clients[i] && clients[i] -> clientState == ClientStateRunning) + { + event.u.u.sequenceNumber = clients[i] -> sequence; + WriteEventsToClient(clients[i], 1, &event); + } + } + + #ifdef XKB + + } + + #endif + +} + +int nxagentResetKeyboard(void) +{ + DeviceIntPtr dev = inputInfo.keyboard; + DeviceIntPtr devBackup; + + int result; + int oldMinKeycode = 8; + int oldMaxKeycode = 255; + + int savedBellPercent; + int savedBellPitch; + int savedBellDuration; + + if (NXDisplayError(nxagentDisplay) == 1) + { + return 0; + } + + /* + * Save bell settings. + */ + + savedBellPercent = inputInfo.keyboard -> kbdfeed -> ctrl.bell; + savedBellPitch = inputInfo.keyboard -> kbdfeed -> ctrl.bell_pitch; + savedBellDuration = inputInfo.keyboard -> kbdfeed -> ctrl.bell_duration; + + #ifdef TEST + fprintf(stderr, "nxagentResetKeyboard: bellPercent [%d] bellPitch [%d] bellDuration [%d].\n", + savedBellPercent, savedBellPitch, savedBellDuration); + #endif + + devBackup = malloc(sizeof(DeviceIntRec)); + + if (devBackup == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentSaveKeyboardDeviceData: PANIC! Can't allocate backup structure.\n"); + #endif + } + else + { + memset(devBackup, 0, sizeof(DeviceIntRec)); + } + + nxagentSaveKeyboardDeviceData(dev, devBackup); + + if (dev->key) + { + #ifdef XKB + if (noXkbExtension == 0 && dev->key->xkbInfo) + { + oldMinKeycode = dev->key->xkbInfo -> desc -> min_key_code; + oldMaxKeycode = dev->key->xkbInfo -> desc -> max_key_code; + } + #endif + + dev->key=NULL; + } + + dev->focus=NULL; + + dev->kbdfeed=NULL; + + #ifdef XKB + nxagentTuneXkbWrapper(); + #endif + + result = (*inputInfo.keyboard -> deviceProc)(inputInfo.keyboard, DEVICE_INIT); + + if (result == Success && inputInfo.keyboard -> key != NULL) + { + + /* + * Restore bell settings. + */ + + inputInfo.keyboard -> kbdfeed -> ctrl.bell = savedBellPercent; + inputInfo.keyboard -> kbdfeed -> ctrl.bell_pitch = savedBellPitch; + inputInfo.keyboard -> kbdfeed -> ctrl.bell_duration = savedBellDuration; + + nxagentNotifyKeyboardChanges(oldMinKeycode, oldMaxKeycode); + + nxagentFreeKeyboardDeviceData(devBackup); + + free(devBackup); + + return 1; + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentResetKeyboard: Can't initialize the keyboard device.\n"); + #endif + + nxagentRestoreKeyboardDeviceData(devBackup, dev); + + return 0; + } +} + +void nxagentCheckModifierMasks(CARD8 keycode, int j) +{ + if (keycode == XKeysymToKeycode(nxagentDisplay, XK_Meta_L)) + { + nxagentAltMetaMask |= 1 << j; + nxagentMetaMask |= 1 << j; + } + + if (keycode == XKeysymToKeycode(nxagentDisplay, XK_Meta_R)) + { + nxagentAltMetaMask |= 1 << j; + nxagentMetaMask |= 1 << j; + } + + if (keycode == XKeysymToKeycode(nxagentDisplay, XK_Alt_L)) + { + nxagentAltMetaMask |= 1 << j; + nxagentAltMask |= 1 << j; + } + + if (keycode == XKeysymToKeycode(nxagentDisplay, XK_Alt_R)) + { + nxagentAltMetaMask |= 1 << j; + nxagentAltMask |= 1 << j; + } + + if (keycode == XKeysymToKeycode(nxagentDisplay, XK_Num_Lock)) + { + nxagentNumlockMask |= 1 << j; + } + + if (keycode == XKeysymToKeycode(nxagentDisplay, XK_Caps_Lock) || + keycode == XKeysymToKeycode(nxagentDisplay, XK_Shift_Lock) ) + { + nxagentCapsMask |= 1 << j; + } + +} + +void nxagentCheckRemoteKeycodes() +{ + nxagentCapsLockKeycode = XKeysymToKeycode(nxagentDisplay, XK_Caps_Lock); + + nxagentNumLockKeycode = XKeysymToKeycode(nxagentDisplay, XK_Num_Lock); + + #ifdef DEBUG + fprintf(stderr, "nxagentCheckRemoteKeycodes: Remote keycodes: CapsLock " + "[%d] NumLock [%d].\n", nxagentCapsLockKeycode, + nxagentNumLockKeycode); + #endif +} + +static int nxagentSaveKeyboardDeviceData(DeviceIntPtr dev, DeviceIntPtr devBackup) +{ + if (devBackup == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentSaveKeyboardDeviceData: PANIC! Pointer to backup structure is null.\n"); + #endif + + return -1; + } + + devBackup -> key = dev -> key; + + devBackup -> focus = dev -> focus; + + devBackup -> kbdfeed = dev -> kbdfeed; + + #ifdef DEBUG + fprintf(stderr, "nxagentSaveKeyboardDeviceData: Saved device data.\n"); + #endif + + return 1; +} + +static int nxagentRestoreKeyboardDeviceData(DeviceIntPtr devBackup, DeviceIntPtr dev) +{ + if (devBackup == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentRestoreKeyboardDeviceData: PANIC! Pointer to backup structure is null.\n"); + #endif + + return -1; + } + + dev -> key = devBackup -> key; + + dev -> focus = devBackup -> focus; + + dev -> kbdfeed = devBackup -> kbdfeed; + + #ifdef DEBUG + fprintf(stderr, "nxagentRestoreKeyboardDeviceData: Restored device data.\n"); + #endif + + return 1; +} + + +static int nxagentFreeKeyboardDeviceData(DeviceIntPtr dev) +{ + KbdFeedbackPtr k, knext; + + if (dev == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentFreeKeyboardDeviceData: PANIC! Pointer to device structure is null.\n"); + #endif + + return -1; + } + + if (dev->key) + { + #ifdef XKB + if (noXkbExtension == 0 && dev->key->xkbInfo) + { + XkbFreeInfo(dev->key->xkbInfo); + dev->key->xkbInfo = NULL; + } + #endif + + free(dev->key->curKeySyms.map); + free(dev->key->modifierKeyMap); + free(dev->key); + + dev->key=NULL; + } + + if (dev->focus) + { + free(dev->focus->trace); + free(dev->focus); + dev->focus=NULL; + } + + for (k = dev->kbdfeed; k; k = knext) + { + knext = k->next; + #ifdef XKB + if (k->xkb_sli) + XkbFreeSrvLedInfo(k->xkb_sli); + #endif + free(k); + } + + #ifdef DEBUG + fprintf(stderr, "nxagentFreeKeyboardDeviceData: Freed device data.\n"); + #endif + + return 1; +} + +#if XKB + +int ProcXkbInhibited(register ClientPtr client) +{ + unsigned char majorop; + unsigned char minorop; + + #ifdef TEST + fprintf(stderr, "ProcXkbInhibited: Called.\n"); + #endif + + majorop = ((xReq *)client->requestBuffer)->reqType; + + #ifdef PANIC + if (majorop != (unsigned char)nxagentXkbWrapper.base) + { + fprintf(stderr, "ProcXkbInhibited: MAJOROP is [%d] but should be [%d].\n", + majorop, nxagentXkbWrapper.base); + } + #endif + + minorop = *((unsigned char *) client->requestBuffer + 1); + + #ifdef TEST + fprintf(stderr, "ProcXkbInhibited: MAJOROP is [%d] MINOROP is [%d].\n", + majorop, minorop); + #endif + + switch (minorop) + { + case X_kbLatchLockState: + case X_kbSetControls: + case X_kbSetCompatMap: + case X_kbSetIndicatorMap: + case X_kbSetNamedIndicator: + case X_kbSetNames: + case X_kbSetGeometry: + case X_kbSetDebuggingFlags: + case X_kbSetMap: + { + return client->noClientException; + } + case X_kbGetKbdByName: + { + return BadAccess; + } + default: + { + return (client->swapped ? nxagentXkbWrapper.SProcXkbDispatchBackup(client) : + nxagentXkbWrapper.ProcXkbDispatchBackup(client)); + } + } +} + +void nxagentInitXkbWrapper(void) +{ + ExtensionEntry * extension; + + #ifdef TEST + fprintf(stderr, "nxagentInitXkbWrapper: Called.\n"); + #endif + + if (nxagentOption(InhibitXkb) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentInitXkbWrapper: Nothing to do.\n"); + #endif + + return; + } + + memset(&nxagentXkbWrapper, 0, sizeof(XkbWrapperRec)); + + extension = CheckExtension("XKEYBOARD"); + + if (extension != NULL) + { + nxagentXkbWrapper.base = extension -> base; + nxagentXkbWrapper.eventBase = extension -> eventBase; + nxagentXkbWrapper.errorBase = extension -> errorBase; + nxagentXkbWrapper.ProcXkbDispatchBackup = NULL; + nxagentXkbWrapper.SProcXkbDispatchBackup = NULL; + + #ifdef TEST + fprintf(stderr, "nxagentInitXkbWrapper: base [%d] eventBase [%d] errorBase [%d].\n", + extension -> base, extension -> eventBase, extension -> errorBase); + #endif + } + else + { + nxagentXkbWrapper.base = -1; + + #ifdef TEST + fprintf(stderr, "nxagentInitXkbWrapper: XKEYBOARD extension not found.\n"); + #endif + } +} + +void nxagentDisableXkbExtension(void) +{ + #ifdef TEST + fprintf(stderr, "nxagentDisableXkbExtension: Called.\n"); + #endif + + if (nxagentXkbWrapper.base > 0) + { + if (nxagentXkbWrapper.ProcXkbDispatchBackup == NULL) + { + nxagentXkbWrapper.ProcXkbDispatchBackup = ProcVector[nxagentXkbWrapper.base]; + + ProcVector[nxagentXkbWrapper.base] = ProcXkbInhibited; + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentDisableXkbExtension: Nothing to be done for ProcXkbDispatch.\n"); + } + #endif + + if (nxagentXkbWrapper.SProcXkbDispatchBackup == NULL) + { + nxagentXkbWrapper.SProcXkbDispatchBackup = SwappedProcVector[nxagentXkbWrapper.base]; + + SwappedProcVector[nxagentXkbWrapper.base] = ProcXkbInhibited; + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentDisableXkbExtension: Nothing to be done for SProcXkbDispatch.\n"); + } + #endif + } +} + +void nxagentEnableXkbExtension(void) +{ + #ifdef TEST + fprintf(stderr, "nxagentEnableXkbExtension: Called.\n"); + #endif + + if (nxagentXkbWrapper.base > 0) + { + if (nxagentXkbWrapper.ProcXkbDispatchBackup != NULL) + { + ProcVector[nxagentXkbWrapper.base] = nxagentXkbWrapper.ProcXkbDispatchBackup; + + nxagentXkbWrapper.ProcXkbDispatchBackup = NULL; + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentEnableXkbExtension: Nothing to be done for ProcXkbDispatch.\n"); + } + #endif + + if (nxagentXkbWrapper.SProcXkbDispatchBackup != NULL) + { + SwappedProcVector[nxagentXkbWrapper.base] = nxagentXkbWrapper.SProcXkbDispatchBackup; + + nxagentXkbWrapper.SProcXkbDispatchBackup = NULL; + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentEnableXkbExtension: Nothing to be done for SProcXkbDispatch.\n"); + } + #endif + } +} + +void nxagentTuneXkbWrapper(void) +{ + if (nxagentOption(InhibitXkb) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentTuneXkbWrapper: Nothing to do.\n"); + #endif + + return; + } + + if (nxagentKeyboard != NULL && + strcmp(nxagentKeyboard, "query") == 0) + { + nxagentDisableXkbExtension(); + } + else + { + nxagentEnableXkbExtension(); + } +} + +static int nxagentXkbGetNames(char **rules, char **model, char **layout, + char **variant, char **options) +{ + Atom atom; + #ifdef _XSERVER64 + Atom64 type; + #else + Atom type; + #endif + int format; + unsigned long n; + unsigned long after; + char *data; + char *name; + Status result; + + data = name = NULL; + + *rules = NULL; + *model = NULL; + *layout = NULL; + *variant = NULL; + *options = NULL; + + atom = XInternAtom(nxagentDisplay, "_XKB_RULES_NAMES", 1); + + if (atom == 0) + { + return 0; + } + + result = XGetWindowProperty(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + atom, 0, 256, 0, XA_STRING, &type, &format, + &n, &after, (unsigned char **)&data); + + if (result !=Success || data == NULL) + { + return 0; + } + + if ((after > 0) || (type != XA_STRING) || (format != 8)) + { + if (data != NULL) + { + XFree(data); + return 0; + } + } + + name = data; + + if (name < data + n) + { + *rules = name; + name += strlen(name) + 1; + } + + if (name < data + n) + { + *model = name; + name += strlen(name) + 1; + } + + if (name < data + n) + { + *layout = name; + name += strlen(name) + 1; + } + + if (name < data + n) + { + *variant = name; + name += strlen(name) + 1; + } + + if (name < data + n) + { + *options = name; + name += strlen(name) + 1; + } + + return n; +} + +void nxagentKeycodeConversionSetup(void) +{ + char *drules = NULL; + char *dmodel = NULL; + char *dlayout = NULL; + char *dvariant = NULL; + char *doptions = NULL; + unsigned int drulesLen; + + nxagentKeycodeConversion = 0; + + drulesLen = nxagentXkbGetNames(&drules, &dmodel, &dlayout, + &dvariant, &doptions); + + #ifdef DEBUG + if (drulesLen != 0 && drules != NULL && dmodel != NULL) + { + fprintf(stderr, "nxagentKeycodeConversionSetup: " + "Remote: [rules='%s',model='%s',layout='%s',variant='%s',options='%s'].\n", + drules, dmodel, dlayout, dvariant, doptions); + } + else + { + fprintf(stderr, "nxagentKeycodeConversionSetup: " + "Failed to retrieve remote rules.\n"); + } + #endif + + if (drulesLen != 0) + { + char *sessionpath = nxagentGetSessionPath(); + if (sessionpath != NULL) + { + int keyboard_file_path_size = strlen(sessionpath) + strlen("/keyboard"); + char *keyboard_file_path = malloc((keyboard_file_path_size + 1) * sizeof(char)); + FILE *keyboard_file; + if (keyboard_file_path == NULL) + { + FatalError("nxagentKeycodeConversionSetup: malloc failed."); + } + strcpy(keyboard_file_path, sessionpath); + strcat(keyboard_file_path, "/keyboard"); + if ((keyboard_file = fopen(keyboard_file_path, "w")) != NULL) { + if (drules != NULL) + fprintf(keyboard_file, "rules=\"%s\"\n", drules[0] == '\0' ? "," : drules); + if (dmodel != NULL) + fprintf(keyboard_file, "model=\"%s\"\n", dmodel[0] == '\0' ? "," : dmodel); + if (dlayout != NULL) + fprintf(keyboard_file, "layout=\"%s\"\n", dlayout[0] == '\0' ? "," : dlayout); + if (dvariant != NULL) + fprintf(keyboard_file, "variant=\"%s\"\n", dvariant[0] == '\0' ? "," : dvariant); + if (doptions != NULL) + fprintf(keyboard_file, "options=\"%s\"\n", doptions[0] == '\0' ? "," : doptions); + fclose(keyboard_file); + fprintf(stderr, "keyboard file created\n"); + } + else + { + int save_err = errno; + fprintf(stderr, "keyboard file not created: %s\n", strerror(save_err)); + } + free(keyboard_file_path); + } + else + { + fprintf(stderr, "SessionPath not defined\n"); + } + } + else + { + fprintf(stderr, "Failed to create the keyboard file\n"); + } + + if (drules != NULL && dmodel != NULL && + (strcmp(drules, "evdev") == 0 || + strcmp(dmodel, "evdev") == 0)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentKeycodeConversionSetup: " + "Activating KeyCode conversion.\n"); + #endif + + nxagentKeycodeConversion = 1; + } + + if (drules != NULL) + { + XFree(drules); + } +} + +void nxagentResetKeycodeConversion(void) +{ + int result; + XkbAgentInfoRec info; + + result = XkbQueryExtension(nxagentDisplay, &info.Opcode, &info.EventBase, + &info.ErrorBase, &info.MajorVersion, + &info.MinorVersion); + + if (result != 0) + { + nxagentKeycodeConversionSetup(); + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentResetKeycodeConversion: " + "WARNING! Failed to query XKB extension.\n"); + #endif + + nxagentKeycodeConversion = 0; + } +} + +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/Keyboard.h b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.h new file mode 100644 index 000000000..ba95a3a22 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Keyboard.h @@ -0,0 +1,135 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Keyboard_H__ +#define __Keyboard_H__ + +#define NXAGENT_KEYBOARD_EVENT_MASK \ + (KeyPressMask | KeyReleaseMask | FocusChangeMask | KeymapStateMask) + +#define NXAGENT_KEYBOARD_EXTENSION_EVENT_MASK \ + (XkbStateNotifyMask) + +/* + * Queried at XKB initialization. + */ + +typedef struct _XkbAgentInfo +{ + int Opcode; + int EventBase; + int ErrorBase; + int MajorVersion; + int MinorVersion; + +} XkbAgentInfoRec; + +extern XkbAgentInfoRec nxagentXkbInfo; + +typedef struct _XkbAgentState +{ + int Locked; + int Caps; + int Num; + int Focus; + int Initialized; + +} XkbAgentStateRec; + +extern XkbAgentStateRec nxagentXkbState; + +/* + * Info for enabling/disabling Xkb. + */ + +typedef struct _XkbWrapper +{ + int base; + int eventBase; + int errorBase; + int (* ProcXkbDispatchBackup)(ClientPtr); + int (* SProcXkbDispatchBackup)(ClientPtr); + +} XkbWrapperRec; + +extern XkbWrapperRec nxagentXkbWrapper; + +extern char *nxagentKeyboard; + +/* + * Keyboard device procedure + * and utility functions. + */ + +void nxagentBell(int volume, DeviceIntPtr pDev, void * ctrl, int cls); + +int nxagentKeyboardProc(DeviceIntPtr pDev, int onoff); + +void nxagentChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl *ctrl); + +void nxagentNotifyKeyboardChanges(int oldMinKeycode, int oldMaxKeycode); + +int nxagentResetKeyboard(void); + +#ifdef XKB + +void nxagentInitXkbWrapper(void); + +void nxagentDisableXkbExtension(void); + +void nxagentEnableXkbExtension(void); + +void nxagentTuneXkbWrapper(void); + +void nxagentResetKeycodeConversion(void); + +#endif + +CARD8 nxagentConvertKeycode(CARD8 k); + +extern CARD8 nxagentCapsLockKeycode; +extern CARD8 nxagentNumLockKeycode; + +extern unsigned int nxagentAltMetaMask; +extern unsigned int nxagentAltMask; +extern unsigned int nxagentMetaMask; +extern unsigned int nxagentCapsMask; +extern unsigned int nxagentNumlockMask; + +#endif /* __Keyboard_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c new file mode 100644 index 000000000..1e3ebca8f --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.c @@ -0,0 +1,662 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "X.h" +#include "keysym.h" + +#include "screenint.h" +#include "scrnintstr.h" + +#include "Agent.h" +#include "Display.h" +#include "Events.h" +#include "Options.h" +#include "Keyboard.h" +#include "Drawable.h" +#include "Init.h" /* extern int nxagentX2go */ +#include "Utils.h" + +#include <unistd.h> + +#include <libxml/parser.h> +#include <libxml/tree.h> + +extern Bool nxagentWMIsRunning; +extern Bool nxagentIpaq; +extern char *nxagentKeystrokeFile; + +#ifdef NX_DEBUG_INPUT +int nxagentDebugInputDevices = False; +unsigned long nxagentLastInputDevicesDumpTime = 0; +extern void nxagentDeactivateInputDevicesGrabs(); +#endif + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +/* must be included _after_ DUMP */ +#include "Keystroke.h" + + +/* this table is used to parse actions given on the command line or in the + * config file, therefore indices have to match the enum in Keystroke.h */ +char * nxagentSpecialKeystrokeNames[] = { + "end_marker", + "close_session", + "switch_all_screens", + "fullscreen", + "minimize", + "defer", + "ignore", + "force_synchronization", + +#ifdef DEBUG_TREE + "debug_tree", +#endif +#ifdef DUMP + "regions_on_screen", +#endif +#ifdef NX_DEBUG_INPUT + "test_input", + "deactivate_input_devices_grab", +#endif + "resize", + "viewport_move_left", + "viewport_move_up", + "viewport_move_right", + "viewport_move_down", + "viewport_scroll_left", + "viewport_scroll_up", + "viewport_scroll_right", + "viewport_scroll_down", + + "reread_keystrokes", + NULL, +}; + +struct nxagentSpecialKeystrokeMap default_map[] = { + /* stroke, modifierMask, modifierAltMeta, keysym */ +#ifdef DEBUG_TREE + {KEYSTROKE_DEBUG_TREE, ControlMask, True, XK_q}, +#endif + {KEYSTROKE_CLOSE_SESSION, ControlMask, True, XK_t}, + {KEYSTROKE_SWITCH_ALL_SCREENS, ControlMask, True, XK_f}, + {KEYSTROKE_FULLSCREEN, ControlMask | ShiftMask, True, XK_f}, + {KEYSTROKE_MINIMIZE, ControlMask, True, XK_m}, + {KEYSTROKE_DEFER, ControlMask, True, XK_e}, + {KEYSTROKE_IGNORE, ControlMask, True, XK_BackSpace}, + {KEYSTROKE_IGNORE, 0, False, XK_Terminate_Server}, + {KEYSTROKE_FORCE_SYNCHRONIZATION, ControlMask, True, XK_j}, +#ifdef DUMP + {KEYSTROKE_REGIONS_ON_SCREEN, ControlMask, True, XK_a}, +#endif +#ifdef NX_DEBUG_INPUT + {KEYSTROKE_TEST_INPUT, ControlMask, True, XK_x}, + {KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB, ControlMask, True, XK_y}, +#endif + {KEYSTROKE_RESIZE, ControlMask, True, XK_r}, + {KEYSTROKE_VIEWPORT_MOVE_LEFT, ControlMask | ShiftMask, True, XK_Left}, + {KEYSTROKE_VIEWPORT_MOVE_LEFT, ControlMask | ShiftMask, True, XK_KP_Left}, + {KEYSTROKE_VIEWPORT_MOVE_UP, ControlMask | ShiftMask, True, XK_Up}, + {KEYSTROKE_VIEWPORT_MOVE_UP, ControlMask | ShiftMask, True, XK_KP_Up}, + {KEYSTROKE_VIEWPORT_MOVE_RIGHT, ControlMask | ShiftMask, True, XK_Right}, + {KEYSTROKE_VIEWPORT_MOVE_RIGHT, ControlMask | ShiftMask, True, XK_KP_Right}, + {KEYSTROKE_VIEWPORT_MOVE_DOWN, ControlMask | ShiftMask, True, XK_Down}, + {KEYSTROKE_VIEWPORT_MOVE_DOWN, ControlMask | ShiftMask, True, XK_KP_Down}, + {KEYSTROKE_VIEWPORT_SCROLL_LEFT, ControlMask, True, XK_Left}, + {KEYSTROKE_VIEWPORT_SCROLL_LEFT, ControlMask, True, XK_KP_Left}, + {KEYSTROKE_VIEWPORT_SCROLL_UP, ControlMask, True, XK_Up}, + {KEYSTROKE_VIEWPORT_SCROLL_UP, ControlMask, True, XK_KP_Up}, + {KEYSTROKE_VIEWPORT_SCROLL_RIGHT, ControlMask, True, XK_Right}, + {KEYSTROKE_VIEWPORT_SCROLL_RIGHT, ControlMask, True, XK_KP_Right}, + {KEYSTROKE_VIEWPORT_SCROLL_DOWN, ControlMask, True, XK_Down}, + {KEYSTROKE_VIEWPORT_SCROLL_DOWN, ControlMask, True, XK_KP_Down}, + {KEYSTROKE_REREAD_KEYSTROKES, ControlMask, True, XK_k}, + {KEYSTROKE_END_MARKER, 0, False, NoSymbol}, +}; +struct nxagentSpecialKeystrokeMap *map = default_map; + +static Bool modifier_matches(unsigned int mask, int compare_alt_meta, unsigned int state) +{ + /* nxagentAltMetaMask needs special handling + * it seems to me its an and-ed mask of all possible meta and alt keys + * somehow... + * + * otherwise this function would be just a simple bitop + */ + Bool ret = True; + + if (compare_alt_meta) { + if (! (state & nxagentAltMetaMask)) { + ret = False; + } + + mask &= ~nxagentAltMetaMask; + state &= ~nxagentAltMetaMask; + } + + /* ignore CapsLock and/or Numlock if the keystroke does not + explicitly require them */ + + if ( !(mask & nxagentCapsMask) ) + state &= ~nxagentCapsMask; + + if ( !(mask & nxagentNumlockMask) ) + state &= ~nxagentNumlockMask; + + /* all modifiers except meta/alt have to match exactly, extra bits are evil */ + if (mask != state) { + ret = False; + } + + return ret; +} + +static Bool read_binding_from_xmlnode(xmlNode *node, struct nxagentSpecialKeystrokeMap *ret) +{ + /* init the struct to have proper values in case not all attributes are found */ + struct nxagentSpecialKeystrokeMap newkm = { + .stroke = KEYSTROKE_NOTHING, + .modifierMask = 0, + .modifierAltMeta = False, + .keysym = NoSymbol + }; + + for (xmlAttr *attr = node->properties; attr; attr = attr->next) + { + /* ignore attributes without data (which should never happen anyways) */ + if (attr->children->content == NULL) + { + #ifdef DEBUG + char *aname = (attr->name)?((char *)attr->name):"unknown"; + fprintf(stderr, "attribute %s with NULL value", aname); + #endif + continue; + } + + if (strcmp((char *)attr->name, "action") == 0) + { + newkm.stroke = KEYSTROKE_NOTHING; + for (int i = 0; nxagentSpecialKeystrokeNames[i] != NULL; i++) + { + if (strcmp(nxagentSpecialKeystrokeNames[i], (char *)attr->children->content) == 0) + { + /* this relies on the values of enum nxagentSpecialKeystroke and the + * indices of nxagentSpecialKeystrokeNames being in sync */ + newkm.stroke = i; + break; + } + } + if (newkm.stroke == KEYSTROKE_NOTHING) + fprintf(stderr, "Info: ignoring unknown keystroke action '%s'.\n", (char *)attr->children->content); + continue; + } + else if (strcmp((char *)attr->name, "key") == 0) + { + newkm.keysym = XStringToKeysym((char *)attr->children->content); + continue; + } + else + { + /* ignore attributes with value="0" or "false", everything else is interpreted as true */ + if (strcmp((char *)attr->children->content, "0") == 0 || strcmp((char *)attr->children->content, "false") == 0) + continue; + + if (strcmp((char *)attr->name, "Mod1") == 0) { newkm.modifierMask |= Mod1Mask; } + else if (strcmp((char *)attr->name, "Mod2") == 0) { newkm.modifierMask |= Mod2Mask; } + else if (strcmp((char *)attr->name, "Mod3") == 0) { newkm.modifierMask |= Mod3Mask; } + else if (strcmp((char *)attr->name, "Mod4") == 0) { newkm.modifierMask |= Mod4Mask; } + else if (strcmp((char *)attr->name, "Mod5") == 0) { newkm.modifierMask |= Mod5Mask; } + else if (strcmp((char *)attr->name, "Control") == 0) { newkm.modifierMask |= ControlMask; } + else if (strcmp((char *)attr->name, "Shift") == 0) { newkm.modifierMask |= ShiftMask; } + else if (strcmp((char *)attr->name, "Lock") == 0) { newkm.modifierMask |= LockMask; } + else if (strcmp((char *)attr->name, "AltMeta") == 0) { newkm.modifierAltMeta = True; } + } + } + + if (newkm.stroke != KEYSTROKE_NOTHING && newkm.keysym != NoSymbol) + { + /* keysym and stroke are required, everything else is optional */ + memcpy(ret, &newkm, sizeof(struct nxagentSpecialKeystrokeMap)); + return True; + } + else + return False; +} + +/* + * searches a keystroke xml file + * + * search order: + * - '-keystrokefile' commandline parameter + * - $NXAGENT_KEYSTROKEFILE environment variable + * - $HOME/.nx/config/keystrokes.cfg + * - /etc/nxagent/keystrokes.cfg + * - hardcoded traditional NX default settings + * If run in x2go flavour different filenames and varnames are used. + */ +void nxagentInitKeystrokes(Bool force) +{ + char *filename = NULL; + + char *homefile; + char *etcfile; + char *envvar; + + /* used for tracking if the config file parsing has already been + done (regardless of the result) */ + static Bool done = False; + + if (force) { + if (map != default_map) + { + free(map); + map = default_map; + } + fprintf(stderr, "Info: re-reading keystrokes configuration\n"); + } + else + { + if (done) + return; + } + + done = True; + + if (nxagentX2go) { + homefile = "/.x2go/config/keystrokes.cfg"; + etcfile = "/etc/x2go/keystrokes.cfg"; + envvar = "X2GO_KEYSTROKEFILE"; + } else { + homefile = "/.nx/config/keystrokes.cfg"; + etcfile = "/etc/nxagent/keystrokes.cfg"; + envvar = "NXAGENT_KEYSTROKEFILE"; + } + + if (nxagentKeystrokeFile && access(nxagentKeystrokeFile, R_OK) == 0) + { + if (!(filename = strdup(nxagentKeystrokeFile))) + { + fprintf(stderr, "malloc failed"); + exit(EXIT_FAILURE); + } + } + else if (nxagentKeystrokeFile) + { + fprintf(stderr, "Warning: Cannot read keystroke file '%s'.\n", nxagentKeystrokeFile); + if ((filename = getenv(envvar)) && access(filename, R_OK) == 0) + { + if (!(filename = strdup(filename))) + { + fprintf(stderr, "malloc failed"); + exit(EXIT_FAILURE); + } + } + else + { + char *homedir = getenv("HOME"); + filename = NULL; + if (homedir) + { + if (!(filename = calloc(1, strlen(homefile) + strlen(homedir) + 1))) + { + fprintf(stderr, "malloc failed"); + exit(EXIT_FAILURE); + } + strcpy(filename, homedir); + strcpy(filename + strlen(homedir), homefile); + } + + if (access(filename, R_OK) == 0) + { + /* empty */ + } + else if (access(etcfile, R_OK) == 0) + { + free(filename); + if (!(filename = strdup(etcfile))) + { + fprintf(stderr, "malloc failed"); + exit(EXIT_FAILURE); + } + } + else + { + free(filename); + filename = NULL; + } + } + } + + /* now we know which file to read, if any */ + if (filename) + { + LIBXML_TEST_VERSION + xmlDoc *doc = xmlReadFile(filename, NULL, 0); + if (doc) + { + fprintf(stderr, "Info: using keystrokes file '%s'\n", filename); + for (xmlNode *cur = xmlDocGetRootElement(doc); cur; cur = cur->next) + { + if (cur->type == XML_ELEMENT_NODE && strcmp((char *)cur->name, "keystrokes") == 0) + { + xmlNode *bindings; + int num = 0; + int idx = 0; + + for (bindings = cur->children; bindings; bindings = bindings->next) + { + if (bindings->type == XML_ELEMENT_NODE && strcmp((char *)bindings->name, "keystroke") == 0) + { + num++; + } + } + #ifdef DEBUG + fprintf(stderr, "%s: found %d keystrokes in %s\n", __func__, num, filename); + #endif + if (!(map = calloc(num+1, sizeof(struct nxagentSpecialKeystrokeMap)))) + { + fprintf(stderr, "calloc failed"); + exit(EXIT_FAILURE); + } + + for (bindings = cur->children; bindings; bindings = bindings->next) + { + map[idx].stroke = KEYSTROKE_NOTHING; + if (bindings->type == XML_ELEMENT_NODE && + strcmp((char *)bindings->name, "keystroke") == 0 && + read_binding_from_xmlnode(bindings, &(map[idx]))) + { + Bool store = True; + for (int j = 0; j < idx; j++) + { + if (map[j].stroke != KEYSTROKE_NOTHING && + map[idx].keysym != NoSymbol && + map[j].keysym == map[idx].keysym && + map[j].modifierMask == map[idx].modifierMask && + map[j].modifierAltMeta == map[idx].modifierAltMeta) + { + fprintf(stderr, "Warning: ignoring keystroke '%s' (already in use by '%s')\n", + nxagentSpecialKeystrokeNames[map[idx].stroke], + nxagentSpecialKeystrokeNames[map[j].stroke]); + store = False; + break; + } + } + + if (store) + idx++; + else + map[idx].stroke = KEYSTROKE_NOTHING; + } + } + #ifdef DEBUG + fprintf(stderr, "%s: read %d keystrokes", __func__, idx); + #endif + + map[idx].stroke = KEYSTROKE_END_MARKER; + } + } + + xmlFreeDoc(doc); + xmlCleanupParser(); + } + else + { + fprintf(stderr, "Warning: could not read/parse keystrokes file '%s'\n", filename); + } + free(filename); + filename = NULL; + } + + if (map == default_map) + { + fprintf(stderr, "Info: Using builtin keystrokes.\n"); + } + + nxagentDumpKeystrokes(); +} + +void nxagentDumpKeystrokes(void) +{ + int maxlen = 0; + for (int i = 0; nxagentSpecialKeystrokeNames[i]; i++) + maxlen = MAX(maxlen, strlen(nxagentSpecialKeystrokeNames[i])); + + fprintf(stderr, "Current known keystrokes:\n"); + + for (struct nxagentSpecialKeystrokeMap *cur = map; cur->stroke != KEYSTROKE_END_MARKER; cur++) { + unsigned int mask = cur->modifierMask; + fprintf(stderr, " %-*s ", maxlen, nxagentSpecialKeystrokeNames[cur->stroke]); + if (mask & ControlMask) {fprintf(stderr, "Ctrl+"); mask &= ~ControlMask;} + if (mask & ShiftMask) {fprintf(stderr, "Shift+"); mask &= ~ShiftMask;} + + /* these are only here for better readable modifier + names. Normally they are covered by the Mod<n> and Lock lines + below */ + if (cur->modifierAltMeta) {fprintf(stderr, "Alt+"); mask &= ~(cur->modifierAltMeta);} + if (mask & nxagentCapsMask) {fprintf(stderr, "CapsLock+"); mask &= ~nxagentCapsMask;} + if (mask & nxagentNumlockMask) {fprintf(stderr, "NumLock+"); mask &= ~nxagentNumlockMask;} + + if (mask & Mod1Mask) {fprintf(stderr, "Mod1+"); mask &= ~Mod1Mask;} + if (mask & Mod2Mask) {fprintf(stderr, "Mod2+"); mask &= ~Mod2Mask;} + if (mask & Mod3Mask) {fprintf(stderr, "Mod3+"); mask &= ~Mod3Mask;} + if (mask & Mod4Mask) {fprintf(stderr, "Mod4+"); mask &= ~Mod4Mask;} + if (mask & Mod5Mask) {fprintf(stderr, "Mod5+"); mask &= ~Mod5Mask;} + if (mask & LockMask) {fprintf(stderr, "Lock+"); mask &= ~LockMask;} + fprintf(stderr, "%s\n", XKeysymToString(cur->keysym)); + } +} + +static enum nxagentSpecialKeystroke find_keystroke(XKeyEvent *X) +{ + enum nxagentSpecialKeystroke ret = KEYSTROKE_NOTHING; + + KeySym keysym = XKeycodeToKeysym(nxagentDisplay, X->keycode, 0); + + + #ifdef DEBUG + fprintf(stderr, "%s: got keysym '%c' (%d)\n", __func__, keysym, keysym); + #endif + for (struct nxagentSpecialKeystrokeMap *cur = map; cur->stroke != KEYSTROKE_END_MARKER; cur++) { + #ifdef DEBUG + fprintf(stderr, "%s: checking keysym '%c' (%d)\n", __func__, cur->keysym, cur->keysym); + #endif + if (cur->keysym == keysym && modifier_matches(cur->modifierMask, cur->modifierAltMeta, X->state)) { + #ifdef DEBUG + fprintf(stderr, "%s: match including modifiers for keysym '%c' (%d), stroke %d (%s)\n", __func__, cur->keysym, cur->keysym, cur->stroke, nxagentSpecialKeystrokeNames[cur->stroke]); + #endif + return cur->stroke; + } + } + + return ret; +} + +Bool nxagentCheckSpecialKeystroke(XKeyEvent *X, enum HandleEventResult *result) +{ + enum nxagentSpecialKeystroke stroke = find_keystroke(X); + *result = doNothing; + + #ifdef TEST + if (stroke != KEYSTROKE_NOTHING && stroke != KEYSTROKE_END_MARKER) + fprintf(stderr, "nxagentCheckSpecialKeystroke: got code %x - state %x - stroke %d (%s)\n", + X -> keycode, X -> state, stroke, nxagentSpecialKeystrokeNames[stroke]); + else + fprintf(stderr, "nxagentCheckSpecialKeystroke: got code %x - state %x - stroke %d (unused)\n", + X -> keycode, X -> state, stroke); + #endif + + if (stroke == KEYSTROKE_NOTHING) + return False; + + /* + * Check special keys. + */ + + /* + * FIXME: We should use the keysym instead that the keycode + * here. + */ + + if (X -> keycode == 130 && nxagentIpaq) + { + *result = doStartKbd; + + return True; + } + + switch (stroke) { +#ifdef DEBUG_TREE + case KEYSTROKE_DEBUG_TREE: + *result = doDebugTree; + break; +#endif + case KEYSTROKE_CLOSE_SESSION: + *result = doCloseSession; + break; + case KEYSTROKE_SWITCH_ALL_SCREENS: + if (!nxagentOption(Rootless)) { + *result = doSwitchAllScreens; + } + break; + case KEYSTROKE_MINIMIZE: + if (!nxagentOption(Rootless)) { + *result = doMinimize; + } + break; + case KEYSTROKE_DEFER: + *result = doSwitchDeferMode; + break; + case KEYSTROKE_IGNORE: + /* this is used e.g. to ignore C-A-Backspace aka XK_Terminate_Server */ + return True; + break; + case KEYSTROKE_FORCE_SYNCHRONIZATION: + nxagentForceSynchronization = 1; + break; +#ifdef DUMP + case KEYSTROKE_REGIONS_ON_SCREEN: + nxagentRegionsOnScreen(); + break; +#endif +#ifdef NX_DEBUG_INPUT + case KEYSTROKE_TEST_INPUT: + /* + * Used to test the input devices state. + */ + if (X -> type == KeyPress) { + if (!nxagentDebugInputDevices) { + fprintf(stderr, "Info: Turning input devices debug ON.\n"); + nxagentDebugInputDevices = True; + } else { + fprintf(stderr, "Info: Turning input devices debug OFF.\n"); + nxagentDebugInputDevices = False; + nxagentLastInputDevicesDumpTime = 0; + } + } + return True; + break; + case KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB: + if (X->type == KeyPress) { + nxagentDeactivateInputDevicesGrab(); + } + return True; + break; +#endif + case KEYSTROKE_FULLSCREEN: + if (!nxagentOption(Rootless)) { + *result = doSwitchFullscreen; + } + break; + case KEYSTROKE_RESIZE: + if (!nxagentOption(Rootless)) { + *result = doSwitchResizeMode; + } + break; + case KEYSTROKE_VIEWPORT_MOVE_LEFT: + if (!nxagentOption(Rootless) && !nxagentOption(DesktopResize)) { + *result = doViewportMoveLeft; + } + break; + case KEYSTROKE_VIEWPORT_MOVE_UP: + if (!nxagentOption(Rootless) && !nxagentOption(DesktopResize)) { + *result = doViewportMoveUp; + } + break; + case KEYSTROKE_VIEWPORT_MOVE_RIGHT: + if (!nxagentOption(Rootless) && !nxagentOption(DesktopResize)) { + *result = doViewportMoveRight; + } + break; + case KEYSTROKE_VIEWPORT_MOVE_DOWN: + if (!nxagentOption(Rootless) && !nxagentOption(DesktopResize)) { + *result = doViewportMoveDown; + } + break; + case KEYSTROKE_VIEWPORT_SCROLL_LEFT: + if (!nxagentOption(Rootless) && !nxagentOption(DesktopResize)) { + *result = doViewportLeft; + } + break; + case KEYSTROKE_VIEWPORT_SCROLL_UP: + if (!nxagentOption(Rootless) && !nxagentOption(DesktopResize)) { + *result = doViewportUp; + } + break; + case KEYSTROKE_VIEWPORT_SCROLL_RIGHT: + if (!nxagentOption(Rootless) && !nxagentOption(DesktopResize)) { + *result = doViewportRight; + } + break; + case KEYSTROKE_VIEWPORT_SCROLL_DOWN: + if (!nxagentOption(Rootless) && !nxagentOption(DesktopResize)) { + *result = doViewportDown; + } + break; + case KEYSTROKE_REREAD_KEYSTROKES: + /* two reasons to check on KeyRelease: + - this code is called for KeyPress and KeyRelease, so we + would read the keystroke file twice + - if the keystroke file changes settings for this key this + might lead to unexpected behaviour + */ + if (X->type == KeyRelease) + nxagentInitKeystrokes(True); + break; + case KEYSTROKE_NOTHING: /* do nothing. difference to KEYSTROKE_IGNORE is the return value */ + case KEYSTROKE_END_MARKER: /* just to make gcc STFU */ + case KEYSTROKE_MAX: + break; + } + return (*result == doNothing); +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h new file mode 100644 index 000000000..13a83d0fe --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Keystroke.h @@ -0,0 +1,90 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Keystroke_H__ +#define __Keystroke_H__ + +#include "Events.h" + +extern Bool nxagentCheckSpecialKeystroke(XKeyEvent*, enum HandleEventResult*); +extern void nxagentDumpKeystrokes(void); +extern void nxagentInitKeystrokes(Bool force); + +/* keep this sorted, do not rely on any numerical value in this enum, and be aware + * that KEYSTROKE_MAX may be used in a malloc */ + +/* also be aware that if changing any numerical values, you also need to change values + * Keystroke.c nxagentSpecialKeystrokeNames */ +enum nxagentSpecialKeystroke { + /* 0 is used as end marker */ + KEYSTROKE_END_MARKER, + KEYSTROKE_CLOSE_SESSION, + KEYSTROKE_SWITCH_ALL_SCREENS, + KEYSTROKE_FULLSCREEN, + KEYSTROKE_MINIMIZE, + KEYSTROKE_DEFER, + KEYSTROKE_IGNORE, + KEYSTROKE_FORCE_SYNCHRONIZATION, + + /* stuff used for debugging, probably not useful for most people */ +#ifdef DEBUG_TREE + KEYSTROKE_DEBUG_TREE, +#endif +#ifdef DUMP + KEYSTROKE_REGIONS_ON_SCREEN, +#endif +#ifdef NX_DEBUG_INPUT + KEYSTROKE_TEST_INPUT, + KEYSTROKE_DEACTIVATE_INPUT_DEVICES_GRAB, +#endif + + /* all the viewport stuff */ + KEYSTROKE_RESIZE, + KEYSTROKE_VIEWPORT_MOVE_LEFT, + KEYSTROKE_VIEWPORT_MOVE_UP, + KEYSTROKE_VIEWPORT_MOVE_RIGHT, + KEYSTROKE_VIEWPORT_MOVE_DOWN, + KEYSTROKE_VIEWPORT_SCROLL_LEFT, + KEYSTROKE_VIEWPORT_SCROLL_UP, + KEYSTROKE_VIEWPORT_SCROLL_RIGHT, + KEYSTROKE_VIEWPORT_SCROLL_DOWN, + + KEYSTROKE_REREAD_KEYSTROKES, + + KEYSTROKE_NOTHING, + + /* insert more here and in the string translation */ + + KEYSTROKE_MAX, +}; + +struct nxagentSpecialKeystrokeMap { + enum nxagentSpecialKeystroke stroke; + unsigned int modifierMask; /* everything except alt/meta */ + Bool modifierAltMeta; /* modifier combination should include alt/meta */ + KeySym keysym; +}; + +#endif /* __Keystroke_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Literals.h b/nx-X11/programs/Xserver/hw/nxagent/Literals.h new file mode 100644 index 000000000..c0bb8c5d7 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Literals.h @@ -0,0 +1,213 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * Simple table used to translate a request + * opcode to the name of the X request. + */ + +static char *nxagentRequestLiteral[] = +{ + "None", + "CreateWindow", + "ChangeWindowAttributes", + "GetWindowAttributes", + "DestroyWindow", + "DestroySubwindows", + "ChangeSaveSet", + "ReparentWindow", + "MapWindow", + "MapSubwindows", + "UnmapWindow", + "UnmapSubwindows", + "ConfigureWindow", + "CirculateWindow", + "GetGeometry", + "QueryTree", + "InternAtom", + "GetAtomName", + "ChangeProperty", + "DeleteProperty", + "GetProperty", + "ListProperties", + "SetSelectionOwner", + "GetSelectionOwner", + "ConvertSelection", + "SendEvent", + "GrabPointer", + "UngrabPointer", + "GrabButton", + "UngrabButton", + "ChangeActivePointerGrab", + "GrabKeyboard", + "UngrabKeyboard", + "GrabKey", + "UngrabKey", + "AllowEvents", + "GrabServer", + "UngrabServer", + "QueryPointer", + "GetMotionEvents", + "TranslateCoords", + "WarpPointer", + "SetInputFocus", + "GetInputFocus", + "QueryKeymap", + "OpenFont", + "CloseFont", + "QueryFont", + "QueryTextExtents", + "ListFonts", + "ListFontsWithInfo", + "SetFontPath", + "GetFontPath", + "CreatePixmap", + "FreePixmap", + "CreateGC", + "ChangeGC", + "CopyGC", + "SetDashes", + "SetClipRectangles", + "FreeGC", + "ClearArea", + "CopyArea", + "CopyPlane", + "PolyPoint", + "PolyLine", + "PolySegment", + "PolyRectangle", + "PolyArc", + "FillPoly", + "PolyFillRectangle", + "PolyFillArc", + "PutImage", + "GetImage", + "PolyText8", + "PolyText16", + "ImageText8", + "ImageText16", + "CreateColormap", + "FreeColormap", + "CopyColormapAndFree", + "InstallColormap", + "UninstallColormap", + "ListInstalledColormaps", + "AllocColor", + "AllocNamedColor", + "AllocColorCells", + "AllocColorPlanes", + "FreeColors", + "StoreColors", + "StoreNamedColor", + "QueryColors", + "LookupColor", + "CreateCursor", + "CreateGlyphCursor", + "FreeCursor", + "RecolorCursor", + "QueryBestSize", + "QueryExtension", + "ListExtensions", + "ChangeKeyboardMapping", + "GetKeyboardMapping", + "ChangeKeyboardControl", + "GetKeyboardControl", + "Bell", + "ChangePointerControl", + "GetPointerControl", + "SetScreenSaver", + "GetScreenSaver", + "ChangeHosts", + "ListHosts", + "SetAccessControl", + "SetCloseDownMode", + "KillClient", + "RotateProperties", + "ForceScreenSaver", + "SetPointerMapping", + "GetPointerMapping", + "SetModifierMapping", + "GetModifierMapping", + "", + "", + "", + "", + "", + "", + "", + "NoOperation" +}; + +static char *nxagentRenderRequestLiteral[] = +{ + "RenderQueryVersion", + "RenderQueryPictFormats", + "RenderQueryPictIndexValues", + "RenderQueryDithers", + "RenderCreatePicture", + "RenderChangePicture", + "RenderSetPictureClipRectangles", + "RenderFreePicture", + "RenderComposite", + "RenderScale", + "RenderTrapezoids", + "RenderTriangles", + "RenderTriStrip", + "RenderTriFan", + "RenderColorTrapezoids", + "RenderColorTriangles", + "RenderTransform", + "RenderCreateGlyphSet", + "RenderReferenceGlyphSet", + "RenderFreeGlyphSet", + "RenderAddGlyphs", + "RenderAddGlyphsFromPicture", + "RenderFreeGlyphs", + "RenderCompositeGlyphs", + "RenderCompositeGlyphs", + "RenderCompositeGlyphs", + "RenderFillRectangles", + "RenderCreateCursor", + "RenderSetPictureTransform", + "RenderQueryFilters", + "RenderSetPictureFilter", + "RenderCreateAnimCursor", + "RenderAddTraps", + "RenderCreateSolidFill", + "RenderCreateLinearGradient", + "RenderCreateRadialGradient", + "RenderCreateConicalGradient" +}; + +static char *nxagentShmRequestLiteral[] = +{ + "ShmQueryVersion", + "ShmAttach", + "ShmDetach", + "ShmPutImage", + "ShmGetImage", + "ShmCreatePixmap" +}; + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Millis.c b/nx-X11/programs/Xserver/hw/nxagent/Millis.c new file mode 100644 index 000000000..ba801b62a --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Millis.c @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <time.h> +#include <stdio.h> + +#include "Xos.h" +#include "Millis.h" + +#ifdef DDXTIME + +CARD32 GetTimeInMillis() +{ + struct timeval ts; + + X_GETTIMEOFDAY(&ts); + + return(ts.tv_sec * 1000) + (ts.tv_usec / 1000); +} + +#endif + +const char *GetTimeAsString() +{ + char *value; + + struct timeval ts; + + X_GETTIMEOFDAY(&ts); + + value = ctime((time_t *) &ts.tv_sec); + + *(value + strlen(value) - 1) = '\0'; + + return value; +} + +const char *GetTimeInMillisAsString() +{ + char *value; + + char tb[25]; + + struct timeval ts; + + X_GETTIMEOFDAY(&ts); + + value = ctime((time_t *) &ts.tv_sec); + + sprintf(tb, "%.8s:%3.3f", value + 11, + (float) ts.tv_usec / 1000); + + strncpy(value, tb, 24); + + return value; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Millis.h b/nx-X11/programs/Xserver/hw/nxagent/Millis.h new file mode 100644 index 000000000..1e76ccbfb --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Millis.h @@ -0,0 +1,38 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Millis_H__ +#define __Millis_H__ + +#include "Xmd.h" + +CARD32 GetTimeInMillis(void); + +const char *GetTimeInMillisAsString(void); + +const char *GetTimeAsString(void); + +#endif /* __Millis_H__ */ + diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXdamage.c b/nx-X11/programs/Xserver/hw/nxagent/NXdamage.c new file mode 100644 index 000000000..ad02e13a8 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXdamage.c @@ -0,0 +1,225 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * $Id: damage.c,v 1.19 2005/10/06 21:55:41 anholt Exp $ + * + * Copyright © 2003 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "regionstr.h" +#include "../../miext/damage/damage.h" +#include <X11/fonts/font.h> + +/* prototypes */ + +static int +damageText (DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned long count, + char *chars, + FontEncoding fontEncoding, + Bool textType); +static int +damagePolyText8(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + char *chars); +static int +damagePolyText16(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars); +static void +damageImageText8(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + char *chars); +static void +damageImageText16(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars); + +#include "../../miext/damage/damage.c" + +static int +damageText (DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned long count, + char *chars, + FontEncoding fontEncoding, + Bool textType) +{ + CharInfoPtr *charinfo; + CharInfoPtr *info; + unsigned long i; + unsigned int n; + int w; + Bool imageblt; + + imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16); + + charinfo = (CharInfoPtr *) malloc(count * sizeof(CharInfoPtr)); + if (!charinfo) + return x; + + GetGlyphs(pGC->font, count, (unsigned char *)chars, + fontEncoding, &i, charinfo); + n = (unsigned int)i; + w = 0; + if (!imageblt) + for (info = charinfo; i--; info++) + w += (*info)->metrics.characterWidth; + + if (n != 0) { + damageDamageChars (pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, n, + charinfo, imageblt, pGC->subWindowMode); + +#ifndef NXAGENT_SERVER + + if (imageblt) + (*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, + FONTGLYPHS(pGC->font)); + else + (*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, x, y, n, charinfo, + FONTGLYPHS(pGC->font)); +#endif + + } + free(charinfo); + return x + w; +} + +static int +damagePolyText8(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + char *chars) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (checkGCDamage (pDrawable, pGC)) + damageText (pDrawable, pGC, x, y, (unsigned long) count, chars, + Linear8Bit, TT_POLY8); + + x = (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, count, chars); + + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); + return x; +} + +static int +damagePolyText16(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (checkGCDamage (pDrawable, pGC)) + damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, + FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, + TT_POLY16); + + x = (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, count, chars); + + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); + return x; +} + +static void +damageImageText8(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + char *chars) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (checkGCDamage (pDrawable, pGC)) + damageText (pDrawable, pGC, x, y, (unsigned long) count, chars, + Linear8Bit, TT_IMAGE8); + + (*pGC->ops->ImageText8)(pDrawable, pGC, x, y, count, chars); + + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + +static void +damageImageText16(DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars) +{ + DAMAGE_GC_OP_PROLOGUE(pGC, pDrawable); + + if (checkGCDamage (pDrawable, pGC)) + damageText (pDrawable, pGC, x, y, (unsigned long) count, (char *) chars, + FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit, + TT_IMAGE16); + + (*pGC->ops->ImageText16)(pDrawable, pGC, x, y, count, chars); + + DAMAGE_GC_OP_EPILOGUE(pGC, pDrawable); +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXdispatch.c b/nx-X11/programs/Xserver/hw/nxagent/NXdispatch.c new file mode 100644 index 000000000..5792a41c5 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXdispatch.c @@ -0,0 +1,1362 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/************************************************************ + +Copyright 1987, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + + +#ifdef __sun +#define False 0 +#define True 1 +#endif + +#include <X11/fonts/fontstruct.h> + +#define GC XlibGC +#include <nx-X11/Xlib.h> +#undef GC + +#include "../../dix/dispatch.c" + +#include "windowstr.h" + +#include "Atoms.h" +#include "Splash.h" +#include "Client.h" +#include "Clipboard.h" +#include "Reconnect.h" +#include "Millis.h" +#include "Font.h" +#include <nx/Shadow.h> +#include "Handlers.h" +#include "Keyboard.h" + +const int nxagentMaxFontNames = 10000; + +char dispatchExceptionAtReset = DE_RESET; + +/* + * This allows the agent to exit if no + * client is connected within a timeout. + */ + +int nxagentClients = 0; + +void nxagentWaitDisplay(void); + +void nxagentListRemoteFonts(const char *, int); + +unsigned int nxagentWMtimeout = 0; +Bool nxagentWMPassed = 0; + +/* + * Timeouts based on screen saver time. + */ + +int nxagentAutoDisconnectTimeout = 0; + +#include "Xatom.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef WATCH + +/* + * Log begin and end of the important handlers. + */ + +#undef BLOCKS + +#ifdef WATCH +#include "unistd.h" +#endif + +#ifdef TEST +#include "Literals.h" +#endif + +#ifdef VIEWPORT_FRAME + +extern WindowPtr nxagentViewportFrameLeft; +extern WindowPtr nxagentViewportFrameRight; +extern WindowPtr nxagentViewportFrameAbove; +extern WindowPtr nxagentViewportFrameBelow; + +#define IsViewportFrame(pWin) ((pWin) == nxagentViewportFrameLeft || \ + (pWin) == nxagentViewportFrameRight || \ + (pWin) == nxagentViewportFrameAbove || \ + (pWin) == nxagentViewportFrameBelow) + +#else + +#define IsViewportFrame(pWin) (0) + +#endif /* #ifdef VIEWPORT_FRAME */ + +extern int nxagentMaxAllowedResets; + +extern int nxagentFindClientResource(int, RESTYPE, void *); + + +void +InitSelections() +{ + if (CurrentSelections) + free(CurrentSelections); + CurrentSelections = (Selection *)NULL; + NumCurrentSelections = 0; + +#ifdef NXAGENT_CLIPBOARD + { + Selection *newsels; + newsels = (Selection *)malloc(2 * sizeof(Selection)); + if (!newsels) + return; + NumCurrentSelections += 2; + CurrentSelections = newsels; + + CurrentSelections[0].selection = XA_PRIMARY; + CurrentSelections[0].lastTimeChanged = ClientTimeToServerTime(0); + CurrentSelections[0].window = screenInfo.screens[0]->root->drawable.id; + CurrentSelections[0].pWin = NULL; + CurrentSelections[0].client = NullClient; + + CurrentSelections[1].selection = MakeAtom("CLIPBOARD", 9, 1); + CurrentSelections[1].lastTimeChanged = ClientTimeToServerTime(0); + CurrentSelections[1].window = screenInfo.screens[0]->root->drawable.id; + CurrentSelections[1].pWin = NULL; + CurrentSelections[1].client = NullClient; + } +#endif + +} + +#define MAJOROP ((xReq *)client->requestBuffer)->reqType + +void +Dispatch(void) +{ + register int *clientReady; /* array of request ready clients */ + register int result; + register ClientPtr client; + register int nready; + register HWEventQueuePtr* icheck = checkForInput; + long start_tick; + + unsigned long currentDispatch = 0; + + nextFreeClientID = 1; + InitSelections(); + nClients = 0; + + /* + * The agent initialization was successfully + * completed. We can now handle our clients. + */ + + #ifdef XKB + + nxagentInitXkbWrapper(); + + nxagentTuneXkbWrapper(); + + #endif + + #ifdef NXAGENT_ONSTART + + /* + * Set NX_WM property (used by NX client to identify + * the agent's window) three seconds since the first + * client connects. + */ + + nxagentWMtimeout = GetTimeInMillis() + 3000; + + #endif + + clientReady = (int *) malloc(sizeof(int) * MaxClients); + if (!clientReady) + return; + + #ifdef WATCH + + fprintf(stderr, "Dispatch: Watchpoint 12.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +#3 1 352 bits (0 KB) -> 236 bits (0 KB) -> 352/1 -> 236/1 = 1.492:1 +#14 1 256 bits (0 KB) -> 101 bits (0 KB) -> 256/1 -> 101/1 = 2.535:1 +#16 1 256 bits (0 KB) -> 26 bits (0 KB) -> 256/1 -> 26/1 = 9.846:1 +#20 2 2 12256 bits (1 KB) -> 56 bits (0 KB) -> 6128/1 -> 28/1 = 218.857:1 +#43 1 256 bits (0 KB) -> 45 bits (0 KB) -> 256/1 -> 45/1 = 5.689:1 +#47 2 2 42304 bits (5 KB) -> 49 bits (0 KB) -> 21152/1 -> 24/1 = 863.347:1 +#98 1 256 bits (0 KB) -> 34 bits (0 KB) -> 256/1 -> 34/1 = 7.529:1 +*/ + + sleep(30); + + #endif + + #ifdef TEST + fprintf(stderr, "Dispatch: Value of dispatchException is [%x].\n", + dispatchException); + + fprintf(stderr, "Dispatch: Value of dispatchExceptionAtReset is [%x].\n", + dispatchExceptionAtReset); + #endif + + if (!(dispatchException & DE_TERMINATE)) + dispatchException = 0; + + while (!dispatchException) + { + if (*icheck[0] != *icheck[1]) + { + ProcessInputEvents(); + FlushIfCriticalOutputPending(); + } + + /* + * Ensure we remove the splash after the timeout. + * Initializing clientReady[0] to -1 will tell + * WaitForSomething() to yield control after the + * timeout set in clientReady[1]. + */ + + clientReady[0] = 0; + + if (nxagentSplashWindow != None || (nxagentOption(Xdmcp) == 1 && nxagentXdmcpUp == 0)) + { + #ifdef TEST + fprintf(stderr, "******Dispatch: Requesting a timeout of [%d] Ms.\n", + NXAGENT_WAKEUP); + #endif + + clientReady[0] = -1; + clientReady[1] = NXAGENT_WAKEUP; + } + + if (serverGeneration > nxagentMaxAllowedResets && + nxagentSessionState == SESSION_STARTING && + (nxagentOption(Xdmcp) == 0 || nxagentXdmcpUp == 1)) + { + #ifdef NX_DEBUG_INPUT + fprintf(stderr, "Session: Session started at '%s' timestamp [%lu].\n", + GetTimeAsString(), GetTimeInMillis()); + #else + fprintf(stderr, "Session: Session started at '%s'.\n", + GetTimeAsString()); + #endif + + nxagentSessionState = SESSION_UP; + saveAgentState("RUNNING"); + } + + #ifdef BLOCKS + fprintf(stderr, "[End dispatch]\n"); + #endif + + nready = WaitForSomething(clientReady); + + #ifdef BLOCKS + fprintf(stderr, "[Begin dispatch]\n"); + #endif + + #ifdef TEST + fprintf(stderr, "******Dispatch: Running with [%d] clients ready.\n", + nready); + #endif + + #ifdef NXAGENT_ONSTART + + currentDispatch = GetTimeInMillis(); + + /* + * If the timeout is expired set the + * selection informing the NX client + * that the agent is ready. + */ + + if (!nxagentWMPassed && (nxagentWMtimeout < currentDispatch)) + { + nxagentRemoveSplashWindow(NULL); + } + + nxagentClients = nClients; + + #endif + + if (nready) + { + clientReady[0] = SmartScheduleClient (clientReady, nready); + nready = 1; + } + /***************** + * Handle events in round robin fashion, doing input between + * each round + *****************/ + + while (!dispatchException && (--nready >= 0)) + { + client = clients[clientReady[nready]]; + if (! client) + { + /* KillClient can cause this to happen */ + continue; + } + /* GrabServer activation can cause this to be true */ + if (grabState == GrabKickout) + { + grabState = GrabActive; + break; + } + isItTimeToYield = FALSE; + + requestingClient = client; + start_tick = SmartScheduleTime; + while (!isItTimeToYield) + { + if (*icheck[0] != *icheck[1]) + { + ProcessInputEvents(); + FlushIfCriticalOutputPending(); + } + if ((SmartScheduleTime - start_tick) >= SmartScheduleSlice) + { + /* Penalize clients which consume ticks */ + if (client->smart_priority > SMART_MIN_PRIORITY) + client->smart_priority--; + break; + } + /* now, finally, deal with client requests */ + + #ifdef TEST + fprintf(stderr, "******Dispatch: Reading request from client [%d].\n", + client->index); + #endif + + result = ReadRequestFromClient(client); + if (result <= 0) + { + if (result < 0) + CloseDownClient(client); + break; + } +#ifdef NXAGENT_SERVER + + #ifdef TEST + + else + { + + if (MAJOROP > 127) + { + fprintf(stderr, "******Dispatch: Read [Extension] request OPCODE#%d MINOR#%d " + "size [%d] client [%d].\n", MAJOROP, *((char *) client->requestBuffer + 1), + client->req_len << 2, client->index); + } + else + { + fprintf(stderr, "******Dispatch: Read [%s] request OPCODE#%d size [%d] client [%d].\n", + nxagentRequestLiteral[MAJOROP], MAJOROP, client->req_len << 2, + client->index); + } + } + + #endif +#endif + + client->sequence++; +#ifdef DEBUG + if ((client->requestLogIndex >= MAX_REQUEST_LOG) || (client->requestLogIndex <= 0)) + client->requestLogIndex = 0; + client->requestLog[client->requestLogIndex] = MAJOROP; + client->requestLogIndex++; +#endif + if (result > (maxBigRequestSize << 2)) + result = BadLength; + else +#ifdef NXAGENT_SERVER + { + result = (* client->requestVector[MAJOROP])(client); + + #ifdef TEST + + if (MAJOROP > 127) + { + fprintf(stderr, "******Dispatch: Handled [Extension] request OPCODE#%d MINOR#%d " + "size [%d] client [%d] result [%d].\n", MAJOROP, + *((char *) client->requestBuffer + 1), client->req_len << 2, + client->index, result); + } + else + { + fprintf(stderr, "******Dispatch: Handled [%s] request OPCODE#%d size [%d] client [%d] " + "result [%d].\n", nxagentRequestLiteral[MAJOROP], MAJOROP, + client->req_len << 2, client->index, result); + } + + #endif + + /* + * Can set isItTimeToYield to force + * the dispatcher to pay attention + * to another client. + */ + + nxagentDispatchHandler(client, client->req_len << 2, 0); + } +#else + result = (* client->requestVector[MAJOROP])(client); +#endif + + + if (!SmartScheduleSignalEnable) + SmartScheduleTime = GetTimeInMillis(); + + if (result != Success) + { + if (client->noClientException != Success) + CloseDownClient(client); + else + SendErrorToClient(client, MAJOROP, + MinorOpcodeOfRequest(client), + client->errorValue, result); + break; + } +#ifdef DAMAGEEXT + FlushIfCriticalOutputPending (); +#endif + } + FlushAllOutput(); + client = clients[clientReady[nready]]; + if (client) + client->smart_stop_tick = SmartScheduleTime; + requestingClient = NULL; + } + dispatchException &= ~DE_PRIORITYCHANGE; + } +#if defined(DDXBEFORERESET) + ddxBeforeReset (); +#endif + if ((dispatchException & DE_RESET) && + (serverGeneration > nxagentMaxAllowedResets)) + { + dispatchException &= ~DE_RESET; + dispatchException |= DE_TERMINATE; + + fprintf(stderr, "Info: Reached threshold of maximum allowed resets.\n"); + } + + nxagentResetAtomMap(); + + if (serverGeneration > nxagentMaxAllowedResets) + { + /* + * The session is terminating. Force an I/O + * error on the display and wait until the + * NX transport is gone. + */ + + fprintf(stderr, "Session: Terminating session at '%s'.\n", GetTimeAsString()); + saveAgentState("TERMINATING"); + + nxagentWaitDisplay(); + + fprintf(stderr, "Session: Session terminated at '%s'.\n", GetTimeAsString()); + } + + if (nxagentOption(Shadow) == 1) + { + NXShadowDestroy(); + } + saveAgentState("TERMINATED"); + + KillAllClients(); + free(clientReady); + dispatchException &= ~DE_RESET; +} + +#undef MAJOROP + +int +ProcReparentWindow(register ClientPtr client) +{ + register WindowPtr pWin, pParent; + REQUEST(xReparentWindowReq); + register int result; + + REQUEST_SIZE_MATCH(xReparentWindowReq); + pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client, + DixWriteAccess); + if (!pWin) + return(BadWindow); + + if (!nxagentWMPassed) + { + nxagentRemoveSplashWindow(pWin); + } + + pParent = (WindowPtr)SecurityLookupWindow(stuff->parent, client, + DixWriteAccess); + if (!pParent) + return(BadWindow); + if (SAME_SCREENS(pWin->drawable, pParent->drawable)) + { + if ((pWin->backgroundState == ParentRelative) && + (pParent->drawable.depth != pWin->drawable.depth)) + return BadMatch; + if ((pWin->drawable.class != InputOnly) && + (pParent->drawable.class == InputOnly)) + return BadMatch; + result = ReparentWindow(pWin, pParent, + (short)stuff->x, (short)stuff->y, client); + if (client->noClientException != Success) + return(client->noClientException); + else + return(result); + } + else + return (BadMatch); +} + + +int +ProcQueryTree(register ClientPtr client) +{ + xQueryTreeReply reply; + int numChildren = 0; + register WindowPtr pChild, pWin, pHead; + Window *childIDs = (Window *)NULL; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pWin = (WindowPtr)SecurityLookupWindow(stuff->id, client, + DixReadAccess); + if (!pWin) + return(BadWindow); + memset(&reply, 0, sizeof(xQueryTreeReply)); + reply.type = X_Reply; + reply.root = pWin->drawable.pScreen->root->drawable.id; + reply.sequenceNumber = client->sequence; + if (pWin->parent) + reply.parent = pWin->parent->drawable.id; + else + reply.parent = (Window)None; + pHead = RealChildHead(pWin); + for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) + { + if (!IsViewportFrame(pChild)) + { + numChildren++; + } + } + if (numChildren) + { + int curChild = 0; + + childIDs = (Window *) malloc(numChildren * sizeof(Window)); + if (!childIDs) + return BadAlloc; + for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) + { + if (!IsViewportFrame(pChild)) + { + childIDs[curChild++] = pChild->drawable.id; + } + } + } + + reply.nChildren = numChildren; + reply.length = (numChildren * sizeof(Window)) >> 2; + + WriteReplyToClient(client, sizeof(xQueryTreeReply), &reply); + if (numChildren) + { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, numChildren * sizeof(Window), childIDs); + free(childIDs); + } + + return(client->noClientException); +} + + +int +ProcSetSelectionOwner(register ClientPtr client) +{ + WindowPtr pWin; + TimeStamp time; + REQUEST(xSetSelectionOwnerReq); + + REQUEST_SIZE_MATCH(xSetSelectionOwnerReq); + UpdateCurrentTime(); + time = ClientTimeToServerTime(stuff->time); + + /* If the client's time stamp is in the future relative to the server's + time stamp, do not set the selection, just return success. */ + if (CompareTimeStamps(time, currentTime) == LATER) + return Success; + if (stuff->window != None) + { + pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client, + DixReadAccess); + if (!pWin) + return(BadWindow); + } + else + pWin = (WindowPtr)None; + if (ValidAtom(stuff->selection)) + { + int i = 0; + + /* + * First, see if the selection is already set... + */ + while ((i < NumCurrentSelections) && + CurrentSelections[i].selection != stuff->selection) + i++; + if (i < NumCurrentSelections) + { + xEvent event; + + /* If the timestamp in client's request is in the past relative + to the time stamp indicating the last time the owner of the + selection was set, do not set the selection, just return + success. */ + if (CompareTimeStamps(time, CurrentSelections[i].lastTimeChanged) + == EARLIER) + return Success; + if (CurrentSelections[i].client && + (!pWin || (CurrentSelections[i].client != client))) + { + event.u.u.type = SelectionClear; + event.u.selectionClear.time = time.milliseconds; + event.u.selectionClear.window = CurrentSelections[i].window; + event.u.selectionClear.atom = CurrentSelections[i].selection; + (void) TryClientEvents (CurrentSelections[i].client, &event, 1, + NoEventMask, NoEventMask /* CantBeFiltered */, + NullGrab); + } + } + else + { + /* + * It doesn't exist, so add it... + */ + Selection *newsels; + + if (i == 0) + newsels = (Selection *)malloc(sizeof(Selection)); + else + newsels = (Selection *)realloc(CurrentSelections, + (NumCurrentSelections + 1) * sizeof(Selection)); + if (!newsels) + return BadAlloc; + NumCurrentSelections++; + CurrentSelections = newsels; + CurrentSelections[i].selection = stuff->selection; + } + CurrentSelections[i].lastTimeChanged = time; + CurrentSelections[i].window = stuff->window; + CurrentSelections[i].pWin = pWin; + CurrentSelections[i].client = (pWin ? client : NullClient); + if (SelectionCallback) + { + SelectionInfoRec info; + + info.selection = &CurrentSelections[i]; + info.kind= SelectionSetOwner; + CallCallbacks(&SelectionCallback, &info); + } + +#ifdef NXAGENT_CLIPBOARD + if ((CurrentSelections[i].pWin != NULL) && + (nxagentOption(Clipboard) != ClipboardNone) && + ((CurrentSelections[i].selection == XA_PRIMARY) || + (CurrentSelections[i].selection == MakeAtom("CLIPBOARD", 9, 0)))) + { + nxagentSetSelectionOwner(&CurrentSelections[i]); + } +#endif + return (client->noClientException); + } + else + { + client->errorValue = stuff->selection; + return (BadAtom); + } +} + + +int +ProcConvertSelection(register ClientPtr client) +{ + Bool paramsOkay; + xEvent event; + WindowPtr pWin; + REQUEST(xConvertSelectionReq); + + REQUEST_SIZE_MATCH(xConvertSelectionReq); + pWin = (WindowPtr)SecurityLookupWindow(stuff->requestor, client, + DixReadAccess); + if (!pWin) + return(BadWindow); + +#ifdef NXAGENT_CLIPBOARD + if (((stuff->selection == XA_PRIMARY) || + (stuff->selection == MakeAtom("CLIPBOARD", 9, 0))) && + nxagentOption(Clipboard) != ClipboardNone) + { + int i = 0; + + while ((i < NumCurrentSelections) && + CurrentSelections[i].selection != stuff->selection) i++; + + if ((i < NumCurrentSelections) && (CurrentSelections[i].window != None)) + { + if (nxagentConvertSelection(client, pWin, stuff->selection, stuff->requestor, + stuff->property, stuff->target, stuff->time)) + { + return (client->noClientException); + } + } + } +#endif + + paramsOkay = (ValidAtom(stuff->selection) && ValidAtom(stuff->target)); + if (stuff->property != None) + paramsOkay &= ValidAtom(stuff->property); + if (paramsOkay) + { + int i; + + i = 0; + while ((i < NumCurrentSelections) && + CurrentSelections[i].selection != stuff->selection) i++; + if ((i < NumCurrentSelections) && + (CurrentSelections[i].window != None) && (CurrentSelections[i].client != NullClient) +#ifdef XCSECURITY + && (!client->CheckAccess || + (* client->CheckAccess)(client, CurrentSelections[i].window, + RT_WINDOW, DixReadAccess, + CurrentSelections[i].pWin)) +#endif + ) + + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = SelectionRequest; + event.u.selectionRequest.time = stuff->time; + event.u.selectionRequest.owner = + CurrentSelections[i].window; + event.u.selectionRequest.requestor = stuff->requestor; + event.u.selectionRequest.selection = stuff->selection; + event.u.selectionRequest.target = stuff->target; + event.u.selectionRequest.property = stuff->property; + if (TryClientEvents( + CurrentSelections[i].client, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab)) + return (client->noClientException); + } + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = SelectionNotify; + event.u.selectionNotify.time = stuff->time; + event.u.selectionNotify.requestor = stuff->requestor; + event.u.selectionNotify.selection = stuff->selection; + event.u.selectionNotify.target = stuff->target; + event.u.selectionNotify.property = None; + (void) TryClientEvents(client, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab); + return (client->noClientException); + } + else + { + client->errorValue = stuff->property; + return (BadAtom); + } +} + + +int +ProcOpenFont(register ClientPtr client) +{ + int err; + char fontReq[256]; + REQUEST(xOpenFontReq); + + REQUEST_FIXED_SIZE(xOpenFontReq, stuff->nbytes); + client->errorValue = stuff->fid; + LEGAL_NEW_RESOURCE(stuff->fid, client); + + memcpy(fontReq,(char *)&stuff[1],(stuff->nbytes<256)?stuff->nbytes:255); + fontReq[stuff->nbytes]=0; + if (strchr(fontReq,'*') || strchr(fontReq,'?')) + { + extern int nxOpenFont(ClientPtr, XID, Mask, unsigned, char*); +#ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "Dispatch: ProcOpenFont try to find a common font with font pattern=%s\n",fontReq); +#endif + nxagentListRemoteFonts(fontReq, nxagentMaxFontNames); + err = nxOpenFont(client, stuff->fid, (Mask) 0, + stuff->nbytes, (char *)&stuff[1]); + } + else + err = OpenFont(client, stuff->fid, (Mask) 0, + stuff->nbytes, (char *)&stuff[1]); + if (err == Success) + { + return(client->noClientException); + } + else + return err; +} + +int +ProcCloseFont(register ClientPtr client) +{ + FontPtr pFont; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pFont = (FontPtr)SecurityLookupIDByType(client, stuff->id, RT_FONT, + DixDestroyAccess); + if (pFont != (FontPtr)NULL) + { + #ifdef NXAGENT_SERVER + + /* + * When a client closes a font the resource + * should not be lost if the reference counter + * is not 0, otherwise the server will not be + * able to find this font looping through the + * resources. + */ + + if (pFont -> refcnt > 0) + { + if (nxagentFindClientResource(serverClient -> index, RT_NX_FONT, pFont) == 0) + { + #ifdef TEST + fprintf(stderr, "ProcCloseFont: Switching resource for font at [%p].\n", + (void *) pFont); + #endif + + nxagentFontPriv(pFont) -> mirrorID = FakeClientID(serverClient -> index); + + AddResource(nxagentFontPriv(pFont) -> mirrorID, RT_NX_FONT, pFont); + + } + #ifdef TEST + else + { + fprintf(stderr, "ProcCloseFont: Found duplicated font at [%p], " + "resource switching skipped.\n", (void *) pFont); + } + #endif + } + + #endif + + FreeResource(stuff->id, RT_NONE); + return(client->noClientException); + } + else + { + client->errorValue = stuff->id; + return (BadFont); + } +} + + +int +ProcListFonts(register ClientPtr client) +{ + char tmp[256]; + + REQUEST(xListFontsReq); + + REQUEST_FIXED_SIZE(xListFontsReq, stuff->nbytes); + memcpy(tmp,(unsigned char *) &stuff[1],(stuff->nbytes<256)?stuff->nbytes:255); + tmp[stuff->nbytes]=0; + +#ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "Dispatch: ListFont request with pattern %s max_names=%d\n",tmp,stuff->maxNames); +#endif + nxagentListRemoteFonts(tmp, stuff -> maxNames < nxagentMaxFontNames ? nxagentMaxFontNames : stuff->maxNames); + return ListFonts(client, (unsigned char *) &stuff[1], stuff->nbytes, + stuff->maxNames); +} + +int +ProcListFontsWithInfo(register ClientPtr client) +{ + char tmp[256]; + REQUEST(xListFontsWithInfoReq); + + REQUEST_FIXED_SIZE(xListFontsWithInfoReq, stuff->nbytes); + + memcpy(tmp,(unsigned char *) &stuff[1],(stuff->nbytes<256)?stuff->nbytes:255); + tmp[stuff->nbytes]=0; +#ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "Dispatch: ListFont with info request with pattern %s max_names=%d\n",tmp,stuff->maxNames); +#endif + nxagentListRemoteFonts(tmp, stuff -> maxNames < nxagentMaxFontNames ? nxagentMaxFontNames :stuff->maxNames); + + return StartListFontsWithInfo(client, stuff->nbytes, + (unsigned char *) &stuff[1], stuff->maxNames); +} + + +int +ProcFreePixmap(register ClientPtr client) +{ + PixmapPtr pMap; + + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + pMap = (PixmapPtr)SecurityLookupIDByType(client, stuff->id, RT_PIXMAP, + DixDestroyAccess); + if (pMap) + { + #ifdef NXAGENT_SERVER + + /* + * When a client releases a pixmap the resource + * should not be lost if the reference counter + * is not 0, otherwise the server will not be + * able to find this pixmap looping through the + * resources. + */ + + if (pMap -> refcnt > 0) + { + if (nxagentFindClientResource(serverClient -> index, RT_NX_PIXMAP, pMap) == 0) + { + #ifdef TEST + fprintf(stderr, "ProcFreePixmap: Switching resource for pixmap at [%p].\n", + (void *) pMap); + #endif + + nxagentPixmapPriv(pMap) -> mid = FakeClientID(serverClient -> index); + + AddResource(nxagentPixmapPriv(pMap) -> mid, RT_NX_PIXMAP, pMap); + } + #ifdef TEST + else + { + fprintf(stderr, "ProcFreePixmap: Found duplicated pixmap at [%p], " + "resource switching skipped.\n", (void *) pMap); + } + #endif + } + + #endif + + FreeResource(stuff->id, RT_NONE); + return(client->noClientException); + } + else + { + client->errorValue = stuff->id; + return (BadPixmap); + } +} + + +int +ProcSetScreenSaver (register ClientPtr client) +{ + int blankingOption, exposureOption; + REQUEST(xSetScreenSaverReq); + + REQUEST_SIZE_MATCH(xSetScreenSaverReq); + blankingOption = stuff->preferBlank; + if ((blankingOption != DontPreferBlanking) && + (blankingOption != PreferBlanking) && + (blankingOption != DefaultBlanking)) + { + client->errorValue = blankingOption; + return BadValue; + } + exposureOption = stuff->allowExpose; + if ((exposureOption != DontAllowExposures) && + (exposureOption != AllowExposures) && + (exposureOption != DefaultExposures)) + { + client->errorValue = exposureOption; + return BadValue; + } + if (stuff->timeout < -1) + { + client->errorValue = stuff->timeout; + return BadValue; + } + if (stuff->interval < -1) + { + client->errorValue = stuff->interval; + return BadValue; + } + + /* + * The NX agent uses the screen saver procedure + * to monitor the user activities and launch its + * handlers (like timeout feature), so we can't + * always allow the clients to change our values. + */ + + #ifdef TEST + fprintf(stderr, "ProcSetScreenSaver: Called with timeout [%d] interval [%d] Blanking [%d] Exposure [%d].\n", + stuff -> timeout, stuff -> interval, blankingOption, exposureOption); + #endif + + if (nxagentOption(Timeout) == 0) + { + if (blankingOption == DefaultBlanking) + { + ScreenSaverBlanking = defaultScreenSaverBlanking; + } + else + { + ScreenSaverBlanking = blankingOption; + } + + if (exposureOption == DefaultExposures) + { + ScreenSaverAllowExposures = defaultScreenSaverAllowExposures; + } + else + { + ScreenSaverAllowExposures = exposureOption; + } + + if (stuff->timeout >= 0) + { + ScreenSaverTime = stuff->timeout * MILLI_PER_SECOND; + } + else + { + ScreenSaverTime = defaultScreenSaverTime; + } + + if (stuff->interval >= 0) + { + ScreenSaverInterval = stuff->interval * MILLI_PER_SECOND; + } + else + { + ScreenSaverInterval = defaultScreenSaverInterval; + } + + SetScreenSaverTimer(); + } + #ifdef TEST + + else + { + fprintf(stderr, "ProcSetScreenSaver: Keeping auto-disconnect timeout set to [%d] seconds.\n", + nxagentOption(Timeout)); + } + + #endif + + return (client->noClientException); +} + + +int ProcForceScreenSaver(register ClientPtr client) +{ + REQUEST(xForceScreenSaverReq); + + REQUEST_SIZE_MATCH(xForceScreenSaverReq); + + if ((stuff->mode != ScreenSaverReset) && + (stuff->mode != ScreenSaverActive)) + { + client->errorValue = stuff->mode; + return BadValue; + } + + /* + * The NX agent uses the screen saver procedure + * to monitor the user activities and launch its + * handlers (like timeout feature), so we can't + * always allow the clients to force the screen + * saver handler execution. + */ + + if (nxagentOption(Timeout) == 0) + { + SaveScreens(SCREEN_SAVER_FORCER, (int)stuff->mode); + } + + #ifdef TEST + + else + { + fprintf(stderr, "ProcForceScreenSaver: Ignoring the client request with mode [%d].\n", + stuff -> mode); + } + + #endif + + return client->noClientException; +} + + +/********************** + * CloseDownClient + * + * Client can either mark his resources destroy or retain. If retained and + * then killed again, the client is really destroyed. + *********************/ + +void +CloseDownClient(register ClientPtr client) +{ + Bool really_close_down = client->clientGone || + client->closeDownMode == DestroyAll; + + /* + * There must be a better way to hook a + * call-back function to be called any + * time a client is going to be closed. + */ + + nxagentClearClipboard(client, NULL); + + /* + * Need to reset the karma counter and + * get rid of the pending sync replies. + */ + + nxagentWakeupByReset(client); + + /* + * Check if the client + * is a shadow nxagent. + */ + + nxagentCheckIfShadowAgent(client); + + if (!client->clientGone) + { + /* ungrab server if grabbing client dies */ + if (grabState != GrabNone && grabClient == client) + { + UngrabServer(client); + } + BITCLEAR(grabWaiters, client->index); + DeleteClientFromAnySelections(client); + ReleaseActiveGrabs(client); + DeleteClientFontStuff(client); + if (!really_close_down) + { + /* This frees resources that should never be retained + * no matter what the close down mode is. Actually we + * could do this unconditionally, but it's probably + * better not to traverse all the client's resources + * twice (once here, once a few lines down in + * FreeClientResources) in the common case of + * really_close_down == TRUE. + */ + FreeClientNeverRetainResources(client); + client->clientState = ClientStateRetained; + if (ClientStateCallback) + { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = (xConnSetupPrefix *)NULL; + clientinfo.setup = (xConnSetup *) NULL; + CallCallbacks((&ClientStateCallback), (void *)&clientinfo); + } + } + client->clientGone = TRUE; /* so events aren't sent to client */ + if (ClientIsAsleep(client)) + ClientSignal (client); + ProcessWorkQueueZombies(); + CloseDownConnection(client); + + /* If the client made it to the Running stage, nClients has + * been incremented on its behalf, so we need to decrement it + * now. If it hasn't gotten to Running, nClients has *not* + * been incremented, so *don't* decrement it. + */ + if (client->clientState != ClientStateInitial && + client->clientState != ClientStateAuthenticating ) + { + --nClients; + } + } + + if (really_close_down) + { + if (client->clientState == ClientStateRunning && nClients == 0) + dispatchException |= dispatchExceptionAtReset; + + client->clientState = ClientStateGone; + if (ClientStateCallback) + { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = (xConnSetupPrefix *)NULL; + clientinfo.setup = (xConnSetup *) NULL; + CallCallbacks((&ClientStateCallback), (void *)&clientinfo); + } + FreeClientResources(client); + if (client->index < nextFreeClientID) + nextFreeClientID = client->index; + clients[client->index] = NullClient; + SmartLastClient = NullClient; + free(client); + + while (!clients[currentMaxClients-1]) + currentMaxClients--; + } +} + +int +InitClientPrivates(ClientPtr client) +{ + register char *ptr; + DevUnion *ppriv; + register unsigned *sizes; + register unsigned size; + register int i; + + if (totalClientSize == sizeof(ClientRec)) + ppriv = (DevUnion *)NULL; + else if (client->index) + ppriv = (DevUnion *)(client + 1); + else + { + ppriv = (DevUnion *)malloc(totalClientSize - sizeof(ClientRec)); + if (!ppriv) + return 0; + } + client->devPrivates = ppriv; + sizes = clientPrivateSizes; + ptr = (char *)(ppriv + clientPrivateLen); + for (i = clientPrivateLen; --i >= 0; ppriv++, sizes++) + { + if ( (size = *sizes) ) + { + ppriv->ptr = (void *)ptr; + ptr += size; + } + else + ppriv->ptr = (void *)NULL; + } + + /* + * Initialize the private members. + */ + + nxagentInitClientPrivates(client); + + return 1; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXdixfonts.c b/nx-X11/programs/Xserver/hw/nxagent/NXdixfonts.c new file mode 100644 index 000000000..49d864887 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXdixfonts.c @@ -0,0 +1,1543 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/************************************************************************ +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +************************************************************************/ +/* The panoramix components contained the following notice */ +/* +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +#include "dixstruct.h" +#include "dixfontstr.h" + +static Bool doOpenFont(ClientPtr client, OFclosurePtr c); +static Bool doListFontsAndAliases(ClientPtr client, LFclosurePtr c); + +#include "../../dix/dixfonts.c" + +/* +#define NXAGENT_DEBUG +*/ + +#include "Agent.h" +#include "Font.h" + +#ifndef NX_TRANS_SOCKET + +#define NX_TRANS_SOCKET + +#endif + +#ifdef NX_TRANS_SOCKET + +char _NXFontPath[1024]; + +/* + * Override the default font path and make + * it configurable at run time, based on + * the NX_FONT environment. + */ + +static const char *_NXGetFontPath(const char *path) +{ + const char *fontEnv; + + /* + * Check the environment only once. + */ + + if (*_NXFontPath != '\0') + { + return _NXFontPath; + } + + fontEnv = getenv("NX_FONT"); + + if (fontEnv != NULL && *fontEnv != '\0') + { + if (strlen(fontEnv) + 1 > 1024) + { +#ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetFontPath: WARNING! Maximum length of font path exceeded.\n"); +#endif + goto _NXGetFontPathError; + } + + strcpy(_NXFontPath, fontEnv); + +#ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetFontPath: Using NX font path [%s].\n", _NXFontPath); +#endif + + return _NXFontPath; + } + +_NXGetFontPathError: + + strncpy(_NXFontPath, path, 1023); + _NXFontPath[1023] = '\0'; + +#ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetFontPath: Using default font path [%s].\n", _NXFontPath); +#endif + + return _NXFontPath; +} + +#endif + +static Bool +doOpenFont(ClientPtr client, OFclosurePtr c) +{ + FontPtr pfont = NullFont; + FontPathElementPtr fpe = NULL; + ScreenPtr pScr; + int err = Successful; + int i; + char *alias, + *newname; + int newlen; + int aliascount = 20; + char nxagentOrigFontName[256]; + int nxagentOrigFontNameLen; + + /* + * Decide at runtime what FontFormat to use. + */ + Mask FontFormat = + + ((screenInfo.imageByteOrder == LSBFirst) ? + BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) | + + ((screenInfo.bitmapBitOrder == LSBFirst) ? + BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) | + + BitmapFormatImageRectMin | + +#if GLYPHPADBYTES == 1 + BitmapFormatScanlinePad8 | +#endif + +#if GLYPHPADBYTES == 2 + BitmapFormatScanlinePad16 | +#endif + +#if GLYPHPADBYTES == 4 + BitmapFormatScanlinePad32 | +#endif + +#if GLYPHPADBYTES == 8 + BitmapFormatScanlinePad64 | +#endif + + BitmapFormatScanlineUnit8; + + + nxagentOrigFontNameLen = (c -> origFontNameLen < 256) ? c -> origFontNameLen : 255; + + memcpy(nxagentOrigFontName, c -> origFontName, nxagentOrigFontNameLen); + + nxagentOrigFontName[nxagentOrigFontNameLen] = 0; + + if (client->clientGone) + { + if (c->current_fpe < c->num_fpes) + { + fpe = c->fpe_list[c->current_fpe]; +#ifdef HAS_XFONT2 + (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe); +#else + (*fpe_functions[fpe->type].client_died) ((void *) client, fpe); +#endif /* HAS_XFONT2 */ + } + err = Successful; + goto bail; + } + while (c->current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current_fpe]; +#ifdef HAS_XFONT2 + err = (*fpe_functions[fpe->type]->open_font) +#else + err = (*fpe_functions[fpe->type].open_font) +#endif /* HAS_XFONT2 */ + ((void *) client, fpe, c->flags, + c->fontname, c->fnamelen, FontFormat, + BitmapFormatMaskByte | + BitmapFormatMaskBit | + BitmapFormatMaskImageRectangle | + BitmapFormatMaskScanLinePad | + BitmapFormatMaskScanLineUnit, + c->fontid, &pfont, &alias, + c->non_cachable_font && c->non_cachable_font->fpe == fpe ? + c->non_cachable_font : + (FontPtr)0); + + if (err == FontNameAlias && alias) { + newlen = strlen(alias); + newname = (char *) realloc(c->fontname, newlen); + if (!newname) { + err = AllocError; + break; + } + memmove(newname, alias, newlen); + c->fontname = newname; + c->fnamelen = newlen; + c->current_fpe = 0; + if (--aliascount <= 0) + break; + continue; + } + if (err == BadFontName) { + c->current_fpe++; + continue; + } + if (err == Suspended) { + if (!c->slept) { + c->slept = TRUE; + ClientSleep(client, (ClientSleepProcPtr)doOpenFont, (void *) c); +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: doOpenFont: client [%lx] sleeping.\n", client); +#endif + } + return TRUE; + } + break; + } + + if (err != Successful) + goto bail; + if (!pfont) { + err = BadFontName; + goto bail; + } + /* check values for firstCol, lastCol, firstRow, and lastRow */ + if (pfont->info.firstCol > pfont->info.lastCol || + pfont->info.firstRow > pfont->info.lastRow || + pfont->info.lastCol - pfont->info.firstCol > 255) { + err = AllocError; + goto bail; + } + if (!pfont->fpe) + pfont->fpe = fpe; + pfont->refcnt++; + if (pfont->refcnt == 1) { + UseFPE(pfont->fpe); + for (i = 0; i < screenInfo.numScreens; i++) { + pScr = screenInfo.screens[i]; + if (pScr->RealizeFont) + { + + /* NXAGENT uses useless screen pointer to pass the original font name + * to realizeFont, could be a source of problems in the future. + */ + + if (!(*pScr->RealizeFont) ((ScreenPtr)nxagentOrigFontName, pfont)) + { + CloseFont (pfont, (Font) 0); + err=BadFontName; + goto bail; + } + } + } + } + if (!AddResource(c->fontid, RT_FONT, (void *) pfont)) { + err = AllocError; + goto bail; + } + if( nxagentFontPriv(pfont) -> mirrorID == 0 ) + { + extern RESTYPE RT_NX_FONT; + + nxagentFontPriv(pfont) -> mirrorID = FakeClientID(0); + if (!AddResource(nxagentFontPriv(pfont) -> mirrorID, RT_NX_FONT, (void *) pfont)) { + FreeResource(c->fontid, RT_NONE); + err = AllocError; + goto bail; + } + } + if (patternCache && pfont != c->non_cachable_font) +#ifdef HAS_XFONT2 + xfont2_cache_font_pattern(patternCache, nxagentOrigFontName, nxagentOrigFontNameLen, +#else + CacheFontPattern(patternCache, nxagentOrigFontName, nxagentOrigFontNameLen, +#endif /* HAS_XFONT2 */ + pfont); +bail: + if (err != Successful && c->client != serverClient) { + SendErrorToClient(c->client, X_OpenFont, 0, + c->fontid, FontToXError(err)); + } + if (c->slept) + { + ClientWakeup(c->client); +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: doOpenFont: client [%lx] wakeup.\n", client); +#endif + } + for (i = 0; i < c->num_fpes; i++) { + FreeFPE(c->fpe_list[i]); + } + free(c->fpe_list); + free(c->fontname); + free(c); + return TRUE; +} + + +static Bool +doListFontsAndAliases(ClientPtr client, LFclosurePtr c) +{ + FontPathElementPtr fpe; + int err = Successful; + FontNamesPtr names = NULL; + char *name, *resolved=NULL; + int namelen, resolvedlen; + int nnames; + int stringLens; + int i; + xListFontsReply reply; + char *bufptr; + char *bufferStart; + int aliascount = 0; + + if (client->clientGone) + { + if (c->current.current_fpe < c->num_fpes) + { + fpe = c->fpe_list[c->current.current_fpe]; +#ifdef HAS_XFONT2 + (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe); +#else + (*fpe_functions[fpe->type].client_died) ((void *) client, fpe); +#endif /* HAS_XFONT2 */ + } + err = Successful; + goto bail; + } + + if (!c->current.patlen) + goto finish; + + while (c->current.current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current.current_fpe]; + err = Successful; + +#ifdef HAS_XFONT2 + if (!fpe_functions[fpe->type]->start_list_fonts_and_aliases) +#else + if (!fpe_functions[fpe->type].start_list_fonts_and_aliases) +#endif /* HAS_XFONT2 */ + { + /* This FPE doesn't support/require list_fonts_and_aliases */ + +#ifdef HAS_XFONT2 + err = (*fpe_functions[fpe->type]->list_fonts) +#else + err = (*fpe_functions[fpe->type].list_fonts) +#endif /* HAS_XFONT2 */ + ((void *) c->client, fpe, c->current.pattern, + c->current.patlen, c->current.max_names - c->names->nnames, + c->names); + + if (err == Suspended) { + if (!c->slept) { + c->slept = TRUE; + ClientSleep(client, + (ClientSleepProcPtr)doListFontsAndAliases, + (void *) c); +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: doListFont (1): client [%lx] sleeping.\n", client); +#endif + } + return TRUE; + } + + err = BadFontName; + } + else + { + /* Start of list_fonts_and_aliases functionality. Modeled + after list_fonts_with_info in that it resolves aliases, + except that the information collected from FPEs is just + names, not font info. Each list_next_font_or_alias() + returns either a name into name/namelen or an alias into + name/namelen and its target name into resolved/resolvedlen. + The code at this level then resolves the alias by polling + the FPEs. */ + + if (!c->current.list_started) { +#ifdef HAS_XFONT2 + err = (*fpe_functions[fpe->type]->start_list_fonts_and_aliases) +#else + err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases) +#endif /* HAS_XFONT2 */ + ((void *) c->client, fpe, c->current.pattern, + c->current.patlen, c->current.max_names - c->names->nnames, + &c->current.private); + if (err == Suspended) { + if (!c->slept) { + ClientSleep(client, + (ClientSleepProcPtr)doListFontsAndAliases, + (void *) c); + c->slept = TRUE; + } + return TRUE; + } + if (err == Successful) + c->current.list_started = TRUE; + } + if (err == Successful) { + char *tmpname; + name = 0; +#ifdef HAS_XFONT2 + err = (*fpe_functions[fpe->type]->list_next_font_or_alias) +#else + err = (*fpe_functions[fpe->type].list_next_font_or_alias) +#endif /* HAS_XFONT2 */ + ((void *) c->client, fpe, &name, &namelen, &tmpname, + &resolvedlen, c->current.private); + if (err == Suspended) { + if (!c->slept) { + ClientSleep(client, + (ClientSleepProcPtr)doListFontsAndAliases, + (void *) c); + c->slept = TRUE; +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: doListFont (2): client [%lx] sleeping.\n", client); +#endif +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: doListFont (3): client [%lx] sleeping.\n", client); +#endif + } + return TRUE; + } + if (err == FontNameAlias) { + if (resolved) free(resolved); + resolved = (char *) malloc(resolvedlen + 1); + if (resolved) + memmove(resolved, tmpname, resolvedlen + 1); + } + } + + if (err == Successful) + { + if (c->haveSaved) + { + if (c->savedName) +#ifdef HAS_XFONT2 + (void)xfont2_add_font_names_name(c->names, c->savedName, +#else + (void)AddFontNamesName(c->names, c->savedName, +#endif /* HAS_XFONT2 */ + c->savedNameLen); + } + else +#ifdef HAS_XFONT2 + (void)xfont2_add_font_names_name(c->names, name, namelen); +#else + (void)AddFontNamesName(c->names, name, namelen); +#endif /* HAS_XFONT2 */ + } + + /* + * When we get an alias back, save our state and reset back to + * the start of the FPE looking for the specified name. As + * soon as a real font is found for the alias, pop back to the + * old state + */ + else if (err == FontNameAlias) { + char tmp_pattern[XLFDMAXFONTNAMELEN]; + /* + * when an alias recurses, we need to give + * the last FPE a chance to clean up; so we call + * it again, and assume that the error returned + * is BadFontName, indicating the alias resolution + * is complete. + */ + memmove(tmp_pattern, resolved, resolvedlen); + if (c->haveSaved) + { + char *tmpname; + int tmpnamelen; + + tmpname = 0; +#ifdef HAS_XFONT2 + (void) (*fpe_functions[fpe->type]->list_next_font_or_alias) +#else + (void) (*fpe_functions[fpe->type].list_next_font_or_alias) +#endif /* HAS_XFONT2 */ + ((void *) c->client, fpe, &tmpname, &tmpnamelen, + &tmpname, &tmpnamelen, c->current.private); + if (--aliascount <= 0) + { + err = BadFontName; + goto ContBadFontName; + } + } + else + { + c->saved = c->current; + c->haveSaved = TRUE; + if (c->savedName) + free(c->savedName); + c->savedName = (char *)malloc(namelen + 1); + if (c->savedName) + memmove(c->savedName, name, namelen + 1); + c->savedNameLen = namelen; + aliascount = 20; + } + memmove(c->current.pattern, tmp_pattern, resolvedlen); + c->current.patlen = resolvedlen; + c->current.max_names = c->names->nnames + 1; + c->current.current_fpe = -1; + c->current.private = 0; + err = BadFontName; + } + } + /* + * At the end of this FPE, step to the next. If we've finished + * processing an alias, pop state back. If we've collected enough + * font names, quit. + */ + if (err == BadFontName) { + ContBadFontName: ; + c->current.list_started = FALSE; + c->current.current_fpe++; + err = Successful; + if (c->haveSaved) + { + if (c->names->nnames == c->current.max_names || + c->current.current_fpe == c->num_fpes) { + c->haveSaved = FALSE; + c->current = c->saved; + /* Give the saved namelist a chance to clean itself up */ + continue; + } + } + if (c->names->nnames == c->current.max_names) + break; + } + } + + /* + * send the reply + */ + if (err != Successful) { + SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err)); + goto bail; + } + +finish: + + names = c->names; + nnames = names->nnames; + client = c->client; + stringLens = 0; + for (i = 0; i < nnames; i++) + stringLens += (names->length[i] <= 255) ? names->length[i] : 0; + + memset(&reply, 0, sizeof(xListFontsReply)); + reply.type = X_Reply; + reply.length = (stringLens + nnames + 3) >> 2; + reply.nFonts = nnames; + reply.sequenceNumber = client->sequence; + + bufptr = bufferStart = (char *) malloc(reply.length << 2); + + if (!bufptr && reply.length) { + SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc); + goto bail; + } + /* + * since WriteToClient long word aligns things, copy to temp buffer and + * write all at once + */ + for (i = 0; i < nnames; i++) { + if (names->length[i] > 255) + reply.nFonts--; + else + { + { + /* dirty hack: don't list to client fonts not existing on the remote side */ + char tmp[256]; + + memcpy(tmp, names->names[i], names->length[i]); + tmp[ names->length[i] ] = 0; + + if (nxagentFontLookUp(tmp) == 0) + { +#ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "doListFontsAndAliases:\n"); + fprintf(stderr, " removing font: %s \n", tmp); +#endif + reply.nFonts--; + stringLens -= names->length[i]; + continue; + } + } + *bufptr++ = names->length[i]; + memmove( bufptr, names->names[i], names->length[i]); + bufptr += names->length[i]; + } + } + nnames = reply.nFonts; + reply.length = (stringLens + nnames + 3) >> 2; + client->pSwapReplyFunc = ReplySwapVector[X_ListFonts]; + WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply); + WriteToClient(client, stringLens + nnames, bufferStart); + free(bufferStart); + +bail: + if (c->slept) + { + ClientWakeup(client); +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: doListFont: client [%lx] wakeup.\n", client); +#endif + } + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->fpe_list); + if (c->savedName) free(c->savedName); +#ifdef HAS_XFONT2 + xfont2_free_font_names(names); +#else + FreeFontNames(names); +#endif /* HAS_XFONT2 */ + free(c); + if (resolved) free(resolved); + return TRUE; +} + +int +ListFonts(ClientPtr client, unsigned char *pattern, unsigned length, + unsigned max_names) +{ + int i; + LFclosurePtr c; + + /* + * The right error to return here would be BadName, however the + * specification does not allow for a Name error on this request. + * Perhaps a better solution would be to return a nil list, i.e. + * a list containing zero fontnames. + */ + if (length > XLFDMAXFONTNAMELEN) + return BadAlloc; + + if (!(c = (LFclosurePtr) malloc(sizeof *c))) + return BadAlloc; + c->fpe_list = (FontPathElementPtr *) + malloc(sizeof(FontPathElementPtr) * num_fpes); + if (!c->fpe_list) { + free(c); + return BadAlloc; + } +#ifdef HAS_XFONT2 + c->names = xfont2_make_font_names_record(max_names < nxagentMaxFontNames ? max_names : nxagentMaxFontNames); +#else + c->names = MakeFontNamesRecord(max_names < nxagentMaxFontNames ? max_names : nxagentMaxFontNames); +#endif /* HAS_XFONT2 */ + if (!c->names) + { + free(c->fpe_list); + free(c); + return BadAlloc; + } + memmove( c->current.pattern, pattern, length); + for (i = 0; i < num_fpes; i++) { + c->fpe_list[i] = font_path_elements[i]; + UseFPE(c->fpe_list[i]); + } + c->client = client; + c->num_fpes = num_fpes; + c->current.patlen = length; + c->current.current_fpe = 0; + c->current.max_names = max_names; + c->current.list_started = FALSE; + c->current.private = 0; + c->haveSaved = FALSE; + c->slept = FALSE; + c->savedName = 0; + doListFontsAndAliases(client, c); + return Success; +} + +int +doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c) +{ + FontPathElementPtr fpe; + int err = Successful; + char *name; + int namelen; + int numFonts; + FontInfoRec fontInfo, + *pFontInfo; + xListFontsWithInfoReply *reply; + int length; + xFontProp *pFP; + int i; + int aliascount = 0; + xListFontsWithInfoReply finalReply; + + if (client->clientGone) + { + if (c->current.current_fpe < c->num_fpes) + { + fpe = c->fpe_list[c->current.current_fpe]; +#ifdef HAS_XFONT2 + (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe); +#else + (*fpe_functions[fpe->type].client_died) ((void *) client, fpe); +#endif /* HAS_XFONT2 */ + } + err = Successful; + goto bail; + } + client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo]; + if (!c->current.patlen) + goto finish; + while (c->current.current_fpe < c->num_fpes) + { + fpe = c->fpe_list[c->current.current_fpe]; + err = Successful; + if (!c->current.list_started) + { +#ifdef HAS_XFONT2 + err = (*fpe_functions[fpe->type]->start_list_fonts_with_info) +#else + err = (*fpe_functions[fpe->type].start_list_fonts_with_info) +#endif /* HAS_XFONT2 */ + (client, fpe, c->current.pattern, c->current.patlen, + c->current.max_names, &c->current.private); + if (err == Suspended) + { + if (!c->slept) + { + ClientSleep(client, (ClientSleepProcPtr)doListFontsWithInfo, c); + c->slept = TRUE; +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: doListFontWinfo (1): client [%lx] sleeping.\n", client); +#endif + } + return TRUE; + } + if (err == Successful) + c->current.list_started = TRUE; + } + if (err == Successful) + { + name = 0; + pFontInfo = &fontInfo; +#ifdef HAS_XFONT2 + err = (*fpe_functions[fpe->type]->list_next_font_with_info) +#else + err = (*fpe_functions[fpe->type].list_next_font_with_info) +#endif /* HAS_XFONT2 */ + (client, fpe, &name, &namelen, &pFontInfo, + &numFonts, c->current.private); + if (err == Suspended) + { + if (!c->slept) + { + ClientSleep(client, + (ClientSleepProcPtr)doListFontsWithInfo, + c); + c->slept = TRUE; +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: doListFontWinfo (2): client [%lx] sleeping.\n", client); +#endif + } + return TRUE; + } + } + /* + * When we get an alias back, save our state and reset back to the + * start of the FPE looking for the specified name. As soon as a real + * font is found for the alias, pop back to the old state + */ + if (err == FontNameAlias) + { + /* + * when an alias recurses, we need to give + * the last FPE a chance to clean up; so we call + * it again, and assume that the error returned + * is BadFontName, indicating the alias resolution + * is complete. + */ + if (c->haveSaved) + { + char *tmpname; + int tmpnamelen; + FontInfoPtr tmpFontInfo; + + tmpname = 0; + tmpFontInfo = &fontInfo; +#ifdef HAS_XFONT2 + (void) (*fpe_functions[fpe->type]->list_next_font_with_info) +#else + (void) (*fpe_functions[fpe->type].list_next_font_with_info) +#endif /* HAS_XFONT2 */ + (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo, + &numFonts, c->current.private); + if (--aliascount <= 0) + { + err = BadFontName; + goto ContBadFontName; + } + } + else + { + c->saved = c->current; + c->haveSaved = TRUE; + c->savedNumFonts = numFonts; + if (c->savedName) + free(c->savedName); + c->savedName = (char *)malloc(namelen + 1); + if (c->savedName) + memmove(c->savedName, name, namelen + 1); + aliascount = 20; + } + memmove(c->current.pattern, name, namelen); + c->current.patlen = namelen; + c->current.max_names = 1; + c->current.current_fpe = 0; + c->current.private = 0; + c->current.list_started = FALSE; + } + /* + * At the end of this FPE, step to the next. If we've finished + * processing an alias, pop state back. If we've sent enough font + * names, quit. Always wait for BadFontName to let the FPE + * have a chance to clean up. + */ + else if (err == BadFontName) + { + ContBadFontName: ; + c->current.list_started = FALSE; + c->current.current_fpe++; + err = Successful; + if (c->haveSaved) + { + if (c->current.max_names == 0 || + c->current.current_fpe == c->num_fpes) + { + c->haveSaved = FALSE; + c->saved.max_names -= (1 - c->current.max_names); + c->current = c->saved; + } + } + else if (c->current.max_names == 0) + break; + } + else if (err == Successful) + { + + if (c->haveSaved) + { + numFonts = c->savedNumFonts; + name = c->savedName; + namelen = strlen(name); + } + + if (nxagentFontLookUp(name) == 0) + { +#ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "doListFontsAndAliases (with info):\n"); + fprintf(stderr, " removing font: %s \n", name); +#endif + continue; + } + + length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp); + reply = c->reply; + if (c->length < length) + { + reply = (xListFontsWithInfoReply *) realloc(c->reply, length); + if (!reply) + { + err = AllocError; + break; + } + memset(reply + c->length, 0, length - c->length); + c->reply = reply; + c->length = length; + } + reply->type = X_Reply; + reply->length = (sizeof *reply - sizeof(xGenericReply) + + pFontInfo->nprops * sizeof(xFontProp) + + namelen + 3) >> 2; + reply->sequenceNumber = client->sequence; + reply->nameLength = namelen; + reply->minBounds = pFontInfo->ink_minbounds; + reply->maxBounds = pFontInfo->ink_maxbounds; + reply->minCharOrByte2 = pFontInfo->firstCol; + reply->maxCharOrByte2 = pFontInfo->lastCol; + reply->defaultChar = pFontInfo->defaultCh; + reply->nFontProps = pFontInfo->nprops; + reply->drawDirection = pFontInfo->drawDirection; + reply->minByte1 = pFontInfo->firstRow; + reply->maxByte1 = pFontInfo->lastRow; + reply->allCharsExist = pFontInfo->allExist; + reply->fontAscent = pFontInfo->fontAscent; + reply->fontDescent = pFontInfo->fontDescent; + reply->nReplies = numFonts; + pFP = (xFontProp *) (reply + 1); + for (i = 0; i < pFontInfo->nprops; i++) + { + pFP->name = pFontInfo->props[i].name; + pFP->value = pFontInfo->props[i].value; + pFP++; + } + WriteSwappedDataToClient(client, length, reply); + WriteToClient(client, namelen, name); + if (pFontInfo == &fontInfo) + { + free(fontInfo.props); + free(fontInfo.isStringProp); + } + --c->current.max_names; + } + } +finish: + length = sizeof(xListFontsWithInfoReply); + bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply)); + finalReply.type = X_Reply; + finalReply.sequenceNumber = client->sequence; + finalReply.length = (sizeof(xListFontsWithInfoReply) + - sizeof(xGenericReply)) >> 2; + WriteSwappedDataToClient(client, length, &finalReply); +bail: + if (c->slept) + { + ClientWakeup(client); +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: doListFontWinfo: client [%lx] wakeup.\n", client); +#endif + } + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->reply); + free(c->fpe_list); + if (c->savedName) free(c->savedName); + free(c); + return TRUE; +} + + +int +SetDefaultFontPath(char *path) +{ + char *temp_path, + *start, + *end; + unsigned char *cp, + *pp, + *nump, + *newpath; + int num = 1, + len, + err, + size = 0, + bad; + +#ifdef NX_TRANS_SOCKET + path = (char *) _NXGetFontPath(path); +#endif /* NX_TRANS_SOCKET */ + + start = path; + + /* ensure temp_path contains "built-ins" */ + while (1) { + start = strstr(start, "built-ins"); + if (start == NULL) + break; + end = start + strlen("built-ins"); + if ((start == path || start[-1] == ',') && (!*end || *end == ',')) + break; + start = end; + } + if (!start) { + if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "") + == -1) + temp_path = NULL; + } + else { + temp_path = strdup(path); + } + if (!temp_path) + return BadAlloc; + + /* get enough for string, plus values -- use up commas */ + len = strlen(temp_path) + 1; + nump = cp = newpath = (unsigned char *) malloc(len); + if (!newpath) { + free(temp_path); + return BadAlloc; + } + pp = (unsigned char *) temp_path; + cp++; + while (*pp) { + if (*pp == ',') { + *nump = (unsigned char) size; + nump = cp++; + pp++; + num++; + size = 0; + } else { + *cp++ = *pp++; + size++; + } + } + *nump = (unsigned char) size; + + err = SetFontPathElements(num, newpath, &bad, TRUE); + + free(newpath); + free(temp_path); + + return err; +} + + +typedef struct +{ + LFclosurePtr c; + OFclosurePtr oc; +} nxFs,*nxFsPtr; + +static Bool +#if NeedFunctionPrototypes +nxdoListFontsAndAliases(ClientPtr client, nxFsPtr fss) +#else +nxdoListFontsAndAliases(client, fss) + ClientPtr client; + nxFsPtr fss; +#endif +{ + LFclosurePtr c=fss->c; + OFclosurePtr oc=fss->oc; + FontPathElementPtr fpe; + int err = Successful; + char *name, *resolved=NULL; + int namelen, resolvedlen; + int i; + int aliascount = 0; + char tmp[256]; + tmp[0]=0; + if (client->clientGone) + { + if (c->current.current_fpe < c->num_fpes) + { + fpe = c->fpe_list[c->current.current_fpe]; +#ifdef HAS_XFONT2 + (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe); +#else + (*fpe_functions[fpe->type].client_died) ((void *) client, fpe); +#endif /* HAS_XFONT2 */ + } + err = Successful; + goto bail; + } + + if (!c->current.patlen) + goto finish; + + while (c->current.current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current.current_fpe]; + err = Successful; + +#ifdef HAS_XFONT2 + if (!fpe_functions[fpe->type]->start_list_fonts_and_aliases) +#else + if (!fpe_functions[fpe->type].start_list_fonts_and_aliases) +#endif /* HAS_XFONT2 */ + { + /* This FPE doesn't support/require list_fonts_and_aliases */ + +#ifdef HAS_XFONT2 + err = (*fpe_functions[fpe->type]->list_fonts) +#else + err = (*fpe_functions[fpe->type].list_fonts) +#endif /* HAS_XFONT2 */ + ((void *) c->client, fpe, c->current.pattern, + c->current.patlen, c->current.max_names - c->names->nnames, + c->names); + + if (err == Suspended) { + if (!c->slept) { + c->slept = TRUE; + ClientSleep(client, + (ClientSleepProcPtr)nxdoListFontsAndAliases, + (void *) fss); +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: nxdoListFont (1): client [%lx] sleeping.\n", client); +#endif + } + return TRUE; + } + + err = BadFontName; + } + else + { + /* Start of list_fonts_and_aliases functionality. Modeled + after list_fonts_with_info in that it resolves aliases, + except that the information collected from FPEs is just + names, not font info. Each list_next_font_or_alias() + returns either a name into name/namelen or an alias into + name/namelen and its target name into resolved/resolvedlen. + The code at this level then resolves the alias by polling + the FPEs. */ + + if (!c->current.list_started) { +#ifdef HAS_XFONT2 + err = (*fpe_functions[fpe->type]->start_list_fonts_and_aliases) +#else + err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases) +#endif /* HAS_XFONT2 */ + ((void *) c->client, fpe, c->current.pattern, + c->current.patlen, c->current.max_names - c->names->nnames, + &c->current.private); + if (err == Suspended) { + if (!c->slept) { + ClientSleep(client, + (ClientSleepProcPtr)nxdoListFontsAndAliases, + (void *) fss); + c->slept = TRUE; +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: nxdoListFont (2): client [%lx] sleeping.\n", client); +#endif + } + return TRUE; + } + if (err == Successful) + c->current.list_started = TRUE; + } + if (err == Successful) { + char *tmpname; + name = 0; +#ifdef HAS_XFONT2 + err = (*fpe_functions[fpe->type]->list_next_font_or_alias) +#else + err = (*fpe_functions[fpe->type].list_next_font_or_alias) +#endif /* HAS_XFONT2 */ + ((void *) c->client, fpe, &name, &namelen, &tmpname, + &resolvedlen, c->current.private); + if (err == Suspended) { + if (!c->slept) { + ClientSleep(client, + (ClientSleepProcPtr)nxdoListFontsAndAliases, + (void *) fss); + c->slept = TRUE; +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: nxdoListFont (3): client [%lx] sleeping.\n", client); +#endif + } + return TRUE; + } + if (err == FontNameAlias) { + if (resolved) free(resolved); + resolved = (char *) malloc(resolvedlen + 1); + if (resolved) + { + memmove(resolved, tmpname, resolvedlen); + resolved[resolvedlen] = '\0'; + } + } + } + + if (err == Successful) + { + if (c->haveSaved) + { + if (c->savedName) + { + memcpy(tmp,c->savedName,c->savedNameLen>255?255:c->savedNameLen); + tmp[c->savedNameLen>255?256:c->savedNameLen]=0; + if (nxagentFontLookUp(tmp)) + break; + else tmp[0]=0; + } + } + else + { + memcpy(tmp,name,namelen>255?255:namelen); + tmp[namelen>255?256:namelen]=0; + if (nxagentFontLookUp(tmp)) + break; + else tmp[0]=0; + } + } + + /* + * When we get an alias back, save our state and reset back to + * the start of the FPE looking for the specified name. As + * soon as a real font is found for the alias, pop back to the + * old state + */ + else if (err == FontNameAlias) { + char tmp_pattern[XLFDMAXFONTNAMELEN]; + /* + * when an alias recurses, we need to give + * the last FPE a chance to clean up; so we call + * it again, and assume that the error returned + * is BadFontName, indicating the alias resolution + * is complete. + */ + memmove(tmp_pattern, resolved, resolvedlen); + if (c->haveSaved) + { + char *tmpname; + int tmpnamelen; + + tmpname = 0; +#ifdef HAS_XFONT2 + (void) (*fpe_functions[fpe->type]->list_next_font_or_alias) +#else + (void) (*fpe_functions[fpe->type].list_next_font_or_alias) +#endif /* HAS_XFONT2 */ + ((void *) c->client, fpe, &tmpname, &tmpnamelen, + &tmpname, &tmpnamelen, c->current.private); + if (--aliascount <= 0) + { + err = BadFontName; + goto ContBadFontName; + } + } + else + { + c->saved = c->current; + c->haveSaved = TRUE; + if (c->savedName) + free(c->savedName); + c->savedName = (char *)malloc(namelen + 1); + if (c->savedName) + { + memmove(c->savedName, name, namelen); + c->savedName[namelen] = '\0'; + } + c->savedNameLen = namelen; + aliascount = 20; + } + memmove(c->current.pattern, tmp_pattern, resolvedlen); + c->current.patlen = resolvedlen; + c->current.max_names = c->names->nnames + 1; + c->current.current_fpe = -1; + c->current.private = 0; + err = BadFontName; + } + } + /* + * At the end of this FPE, step to the next. If we've finished + * processing an alias, pop state back. If we've collected enough + * font names, quit. + */ + if (err == BadFontName) { + ContBadFontName: ; + c->current.list_started = FALSE; + c->current.current_fpe++; + err = Successful; + if (c->haveSaved) + { + if (c->names->nnames == c->current.max_names || + c->current.current_fpe == c->num_fpes) { + c->haveSaved = FALSE; + c->current = c->saved; + /* Give the saved namelist a chance to clean itself up */ + continue; + } + } + if (c->names->nnames == c->current.max_names) + break; + } + } + + /* + * send the reply + */ +bail: +finish: + if (strlen(tmp)) + { +#ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "nxListFont changed (0) font to %s\n",tmp); +#endif + memcpy(oc->fontname, tmp, strlen(tmp)); + oc->fnamelen = strlen(tmp); + + oc->origFontName = oc->fontname; + oc->origFontNameLen = oc->fnamelen; + + } + else + { + for (i = 0; i < c->names->nnames; i++) + { + if (c->names->length[i] > 255) + continue; + else + { + memcpy(tmp, c->names->names[i], c->names->length[i]); + tmp[ c->names->length[i] ] = 0; + if (nxagentFontLookUp(tmp) == 0) + continue; + memcpy(oc->fontname, tmp, strlen(tmp)); + oc->fnamelen = strlen(tmp); + + oc->origFontName = oc->fontname; + oc->origFontNameLen = oc->fnamelen; + +#ifdef NXAGENT_FONTMATCH_DEBUG + fprintf(stderr, "nxListFont changed (1) font to %s\n",tmp); +#endif + break; + } + } + } + + if (c->slept) + { + ClientWakeup(client); +#ifdef NXAGENT_DEBUG + fprintf(stderr, " NXdixfonts: nxdoListFont: client [%lx] wakeup.\n", client); +#endif + } + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->fpe_list); + if (c->savedName) free(c->savedName); +#ifdef HAS_XFONT2 + xfont2_free_font_names(c->names); +#else + FreeFontNames(c->names); +#endif /* HAS_XFONT2 */ + free(c); + free(fss); + if (resolved) free(resolved); + + return doOpenFont(client, oc); +} + +int +nxOpenFont(client, fid, flags, lenfname, pfontname) + ClientPtr client; + XID fid; + Mask flags; + unsigned lenfname; + char *pfontname; +{ + nxFsPtr fss; + LFclosurePtr c; + OFclosurePtr oc; + int i; + FontPtr cached = (FontPtr)0; + +#ifdef FONTDEBUG + char *f; + f = (char *)malloc(lenfname + 1); + memmove(f, pfontname, lenfname); + f[lenfname] = '\0'; + ErrorF("OpenFont: fontname is \"%s\"\n", f); + free(f); +#endif + if (!lenfname || lenfname > XLFDMAXFONTNAMELEN) + return BadName; + if (patternCache) + { + + /* + ** Check name cache. If we find a cached version of this font that + ** is cachable, immediately satisfy the request with it. If we find + ** a cached version of this font that is non-cachable, we do not + ** satisfy the request with it. Instead, we pass the FontPtr to the + ** FPE's open_font code (the fontfile FPE in turn passes the + ** information to the rasterizer; the fserve FPE ignores it). + ** + ** Presumably, the font is marked non-cachable because the FPE has + ** put some licensing restrictions on it. If the FPE, using + ** whatever logic it relies on, determines that it is willing to + ** share this existing font with the client, then it has the option + ** to return the FontPtr we passed it as the newly-opened font. + ** This allows the FPE to exercise its licensing logic without + ** having to create another instance of a font that already exists. + */ + +#ifdef HAS_XFONT2 + cached = xfont2_find_cached_font_pattern(patternCache, pfontname, lenfname); +#else + cached = FindCachedFontPattern(patternCache, pfontname, lenfname); +#endif /* HAS_XFONT2 */ + if (cached && cached->info.cachable) + { + if (!AddResource(fid, RT_FONT, (void *) cached)) + return BadAlloc; + cached->refcnt++; + return Success; + } + } + if (!(fss = (nxFsPtr) malloc(sizeof(nxFs)))) + return BadAlloc; + + if (!(c = (LFclosurePtr) malloc(sizeof *c))) + { + free(fss); + return BadAlloc; + } + c->fpe_list = (FontPathElementPtr *) + malloc(sizeof(FontPathElementPtr) * num_fpes); + if (!c->fpe_list) { + free(c); + free(fss); + return BadAlloc; + } +#ifdef HAS_XFONT2 + c->names = xfont2_make_font_names_record(100); +#else + c->names = MakeFontNamesRecord(100); +#endif /* HAS_XFONT2 */ + if (!c->names) + { + free(c->fpe_list); + free(c); + free(fss); + return BadAlloc; + } + memmove( c->current.pattern, pfontname, lenfname); + for (i = 0; i < num_fpes; i++) { + c->fpe_list[i] = font_path_elements[i]; + UseFPE(c->fpe_list[i]); + } + c->client = client; + c->num_fpes = num_fpes; + c->current.patlen = lenfname; + c->current.current_fpe = 0; + c->current.max_names = nxagentMaxFontNames; + c->current.list_started = FALSE; + c->current.private = 0; + c->haveSaved = FALSE; + c->slept = FALSE; + c->savedName = 0; + + oc = (OFclosurePtr) malloc(sizeof(OFclosureRec)); + if (!oc) + { + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->fpe_list); + free(c); + free(fss); + return BadAlloc; + } + oc->fontname = (char *) malloc(256);/* I don't want to deal with future reallocs errors */ + oc->origFontName = pfontname; + oc->origFontNameLen = lenfname; + if (!oc->fontname) { + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->fpe_list); + free(c); + free(oc); + free(fss); + return BadAlloc; + } + /* + * copy the current FPE list, so that if it gets changed by another client + * while we're blocking, the request still appears atomic + */ + oc->fpe_list = (FontPathElementPtr *) + malloc(sizeof(FontPathElementPtr) * num_fpes); + if (!oc->fpe_list) { + free(oc->fontname); + free(oc); + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->fpe_list); + free(c); + free(fss); + return BadAlloc; + } + memmove(oc->fontname, pfontname, lenfname); + for (i = 0; i < num_fpes; i++) { + oc->fpe_list[i] = font_path_elements[i]; + UseFPE(oc->fpe_list[i]); + } + oc->client = client; + oc->fontid = fid; + oc->current_fpe = 0; + oc->num_fpes = num_fpes; + oc->fnamelen = lenfname; + oc->slept = FALSE; + oc->flags = flags; + oc->non_cachable_font = cached; + fss->c=c; + fss->oc=oc; + nxdoListFontsAndAliases(client, fss); + return Success; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXevents.c b/nx-X11/programs/Xserver/hw/nxagent/NXevents.c new file mode 100644 index 000000000..43cb806e7 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXevents.c @@ -0,0 +1,613 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/************************************************************ + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +/***************************************************************** + +Copyright 2003-2005 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL +INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +******************************************************************/ + + +#include <nx-X11/Xlib.h> + +#include "../../dix/events.c" + +#include "compext/Compext.h" + +#include "Events.h" +#include "Windows.h" +#include "Args.h" + +extern Display *nxagentDisplay; + +extern WindowPtr nxagentLastEnteredWindow; + +void +ActivatePointerGrab(register DeviceIntPtr mouse, register GrabPtr grab, + TimeStamp time, Bool autoGrab) +{ + WindowPtr oldWin = (mouse->grab) ? mouse->grab->window + : sprite.win; + + if (grab->confineTo) + { + if (grab->confineTo->drawable.pScreen != sprite.hotPhys.pScreen) + sprite.hotPhys.x = sprite.hotPhys.y = 0; + ConfineCursorToWindow(grab->confineTo, FALSE, TRUE); + } + DoEnterLeaveEvents(oldWin, grab->window, NotifyGrab); + mouse->valuator->motionHintWindow = NullWindow; + if (syncEvents.playingEvents) + mouse->grabTime = syncEvents.time; + else + mouse->grabTime = time; + if (grab->cursor) + grab->cursor->refcnt++; + mouse->activeGrab = *grab; + mouse->grab = &mouse->activeGrab; + mouse->fromPassiveGrab = autoGrab; + PostNewCursor(); + CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode); + + #ifdef NXAGENT_SERVER + + /* + * If grab is synchronous, events are delivered to clients only if they send + * an AllowEvent request. If mode field in AllowEvent request is SyncPointer, the + * delivered event is saved in a queue and replayed later, when grab is released. + * We should export sync grab to X as async in order to avoid events to be + * queued twice, in the agent and in the X server. This solution have a drawback: + * replayed events are not delivered to that application that are not clients of + * the agent. + * A different solution could be to make the grab asynchronous in the agent and + * to export it as synchronous. But this seems to be less safe. + * + * To make internal grab asynchronous, change previous line as follows. + * + * if (nxagentOption(Rootless)) + * { + * CheckGrabForSyncs(mouse, GrabModeAsync, (Bool)grab->keyboardMode); + * } + * else + * { + * CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode); + * } + */ + + if (nxagentOption(Rootless) == 1) + { + /* + * FIXME: We should use the correct value + * for the cursor. Temporarily we set it + * to None. + */ + + int resource = nxagentWaitForResource(NXGetCollectGrabPointerResource, + nxagentCollectGrabPointerPredicate); + + NXCollectGrabPointer(nxagentDisplay, resource, nxagentWindow(grab -> window), + 1, grab -> eventMask & PointerGrabMask, + GrabModeAsync, GrabModeAsync, (grab -> confineTo) ? + nxagentWindow(grab -> confineTo) : None, + None, CurrentTime); + } + + #endif +} + +void +DeactivatePointerGrab(register DeviceIntPtr mouse) +{ + register GrabPtr grab = mouse->grab; + register DeviceIntPtr dev; + + mouse->valuator->motionHintWindow = NullWindow; + mouse->grab = NullGrab; + mouse->sync.state = NOT_GRABBED; + mouse->fromPassiveGrab = FALSE; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->sync.other == grab) + dev->sync.other = NullGrab; + } + DoEnterLeaveEvents(grab->window, sprite.win, NotifyUngrab); + if (grab->confineTo) + ConfineCursorToWindow(ROOT, FALSE, FALSE); + PostNewCursor(); + if (grab->cursor) + FreeCursor(grab->cursor, (Cursor)0); + ComputeFreezes(); + + #ifdef NXAGENT_SERVER + + if (nxagentOption(Rootless) == 1) + { + XUngrabPointer(nxagentDisplay, CurrentTime); + + if (sprite.win == ROOT) + { + mouse -> button -> state &= + ~(Button1Mask | Button2Mask | Button3Mask | + Button4Mask | Button5Mask); + } + } + + #endif +} + +// int +// ProcAllowEvents(register ClientPtr client) +// { +// TimeStamp time; +// DeviceIntPtr mouse = inputInfo.pointer; +// DeviceIntPtr keybd = inputInfo.keyboard; +// REQUEST(xAllowEventsReq); +// +// REQUEST_SIZE_MATCH(xAllowEventsReq); +// time = ClientTimeToServerTime(stuff->time); +// switch (stuff->mode) +// { +// case ReplayPointer: +// AllowSome(client, time, mouse, NOT_GRABBED); +// break; +// case SyncPointer: +// AllowSome(client, time, mouse, FREEZE_NEXT_EVENT); +// break; +// case AsyncPointer: +// AllowSome(client, time, mouse, THAWED); +// break; +// case ReplayKeyboard: +// AllowSome(client, time, keybd, NOT_GRABBED); +// break; +// case SyncKeyboard: +// AllowSome(client, time, keybd, FREEZE_NEXT_EVENT); +// break; +// case AsyncKeyboard: +// AllowSome(client, time, keybd, THAWED); +// break; +// case SyncBoth: +// AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT); +// break; +// case AsyncBoth: +// AllowSome(client, time, keybd, THAWED_BOTH); +// break; +// default: +// client->errorValue = stuff->mode; +// return BadValue; +// } +// +// /* +// * This is not necessary if we export grab to X as asynchronous. +// * +// * if (nxagentOption(Rootless) && stuff -> mode != ReplayKeyboard && +// * stuff -> mode != SyncKeyboard && stuff -> mode != AsyncKeyboard) +// * { +// * XAllowEvents(nxagentDisplay, stuff -> mode, CurrentTime); +// * } +// */ +// +// return Success; +// } + +static WindowPtr +XYToWindow(int x, int y) +{ + register WindowPtr pWin; + BoxRec box; + + spriteTraceGood = 1; /* root window still there */ + + if (nxagentOption(Rootless)) + { + if (nxagentLastEnteredWindow == NULL) + { + return ROOT; + } + + pWin = ROOT->lastChild; + + while (pWin && pWin != ROOT->firstChild && pWin != nxagentLastEnteredWindow) + { + pWin = pWin->prevSib; + } + } + else + { + pWin = ROOT->firstChild; + } + + while (pWin) + { + if ((pWin->mapped) && + (x >= pWin->drawable.x - wBorderWidth (pWin)) && + (x < pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth(pWin)) && + (y >= pWin->drawable.y - wBorderWidth (pWin)) && + (y < pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin)) +#ifdef SHAPE + /* When a window is shaped, a further check + * is made to see if the point is inside + * borderSize + */ + && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y)) + && (!wInputShape(pWin) || + RegionContainsPoint( + wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box)) +#endif + ) + { + if (spriteTraceGood >= spriteTraceSize) + { + spriteTraceSize += 10; + Must_have_memory = TRUE; /* XXX */ + spriteTrace = (WindowPtr *)realloc( + spriteTrace, spriteTraceSize*sizeof(WindowPtr)); + Must_have_memory = FALSE; /* XXX */ + } + spriteTrace[spriteTraceGood++] = pWin; + pWin = pWin->firstChild; + } + else + pWin = pWin->nextSib; + } + return spriteTrace[spriteTraceGood-1]; +} + +// static Bool +// CheckMotion(xEvent *xE) +// { +// WindowPtr prevSpriteWin = sprite.win; +// +#ifdef PANORAMIX +// if(!noPanoramiXExtension) +// return XineramaCheckMotion(xE); +#endif + +// if (xE && !syncEvents.playingEvents) +// { +// if (sprite.hot.pScreen != sprite.hotPhys.pScreen) +// { +// sprite.hot.pScreen = sprite.hotPhys.pScreen; +// ROOT = sprite.hot.pScreen->root; +// } +// sprite.hot.x = XE_KBPTR.rootX; +// sprite.hot.y = XE_KBPTR.rootY; +// if (sprite.hot.x < sprite.physLimits.x1) +// sprite.hot.x = sprite.physLimits.x1; +// else if (sprite.hot.x >= sprite.physLimits.x2) +// sprite.hot.x = sprite.physLimits.x2 - 1; +// if (sprite.hot.y < sprite.physLimits.y1) +// sprite.hot.y = sprite.physLimits.y1; +// else if (sprite.hot.y >= sprite.physLimits.y2) +// sprite.hot.y = sprite.physLimits.y2 - 1; +#ifdef SHAPE +// if (sprite.hotShape) +// ConfineToShape(sprite.hotShape, &sprite.hot.x, &sprite.hot.y); +#endif +// sprite.hotPhys = sprite.hot; +// +// /* +// * This code force cursor position to be inside the +// * root window of the agent. We can't view a reason +// * to do this and it interacts in an undesirable way +// * with toggling fullscreen. +// * +// * if ((sprite.hotPhys.x != XE_KBPTR.rootX) || +// * (sprite.hotPhys.y != XE_KBPTR.rootY)) +// * { +// * (*sprite.hotPhys.pScreen->SetCursorPosition)( +// * sprite.hotPhys.pScreen, +// * sprite.hotPhys.x, sprite.hotPhys.y, FALSE); +// * } +// */ +// +// XE_KBPTR.rootX = sprite.hot.x; +// XE_KBPTR.rootY = sprite.hot.y; +// } +// +// sprite.win = XYToWindow(sprite.hot.x, sprite.hot.y); +#ifdef notyet +// if (!(sprite.win->deliverableEvents & +// Motion_Filter(inputInfo.pointer->button)) +// !syncEvents.playingEvents) +// { +// /* XXX Do PointerNonInterestBox here */ +// } +#endif +// if (sprite.win != prevSpriteWin) +// { +// if (prevSpriteWin != NullWindow) { +// if (!xE) +// UpdateCurrentTimeIf(); +// DoEnterLeaveEvents(prevSpriteWin, sprite.win, NotifyNormal); +// } +// PostNewCursor(); +// return FALSE; +// } +// return TRUE; +// } + +void +DefineInitialRootWindow(register WindowPtr win) +{ + register ScreenPtr pScreen = win->drawable.pScreen; + #ifdef VIEWPORT_FRAME + extern void nxagentInitViewportFrame(ScreenPtr, WindowPtr); + #endif + extern int nxagentShadowInit(ScreenPtr, WindowPtr); + + sprite.hotPhys.pScreen = pScreen; + sprite.hotPhys.x = pScreen->width / 2; + sprite.hotPhys.y = pScreen->height / 2; + sprite.hot = sprite.hotPhys; + sprite.hotLimits.x2 = pScreen->width; + sprite.hotLimits.y2 = pScreen->height; + sprite.win = win; + sprite.current = wCursor (win); + sprite.current->refcnt++; + spriteTraceGood = 1; + ROOT = win; + (*pScreen->CursorLimits) ( + pScreen, sprite.current, &sprite.hotLimits, &sprite.physLimits); + sprite.confined = FALSE; + (*pScreen->ConstrainCursor) (pScreen, &sprite.physLimits); + (*pScreen->SetCursorPosition) (pScreen, sprite.hot.x, sprite.hot.y, FALSE); + (*pScreen->DisplayCursor) (pScreen, sprite.current); + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + sprite.hotLimits.x1 = -panoramiXdataPtr[0].x; + sprite.hotLimits.y1 = -panoramiXdataPtr[0].y; + sprite.hotLimits.x2 = PanoramiXPixWidth - panoramiXdataPtr[0].x; + sprite.hotLimits.y2 = PanoramiXPixHeight - panoramiXdataPtr[0].y; + sprite.physLimits = sprite.hotLimits; + sprite.confineWin = NullWindow; +#ifdef SHAPE + sprite.hotShape = NullRegion; +#endif + sprite.screen = pScreen; + /* gotta UNINIT these someplace */ + RegionNull(&sprite.Reg1); + RegionNull(&sprite.Reg2); + } +#endif + + #ifdef VIEWPORT_FRAME + nxagentInitViewportFrame(pScreen, win); + #endif + + if (nxagentOption(Shadow)) + { + if (nxagentShadowInit(pScreen, win) == -1) + { + FatalError("Failed to connect to display '%s'", nxagentShadowDisplayName); + } + } +} + +int +ProcSendEvent(ClientPtr client) +{ + WindowPtr pWin; + WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ + REQUEST(xSendEventReq); + + REQUEST_SIZE_MATCH(xSendEventReq); + + /* The client's event type must be a core event type or one defined by an + extension. */ + + +#ifdef NXAGENT_CLIPBOARD + + if (stuff -> event.u.u.type == SelectionNotify) + { + extern int nxagentSendNotify(xEvent*); + if (nxagentSendNotify(&stuff->event) == 1) + return Success; + } +#endif + + if ( ! ((stuff->event.u.u.type > X_Reply && + stuff->event.u.u.type < LASTEvent) || + (stuff->event.u.u.type >= EXTENSION_EVENT_BASE && + stuff->event.u.u.type < (unsigned)lastEvent))) + { + client->errorValue = stuff->event.u.u.type; + return BadValue; + } + if (stuff->event.u.u.type == ClientMessage && + stuff->event.u.u.detail != 8 && + stuff->event.u.u.detail != 16 && + stuff->event.u.u.detail != 32 && + !permitOldBugs) + { + client->errorValue = stuff->event.u.u.detail; + return BadValue; + } + if ((stuff->eventMask & ~AllEventMasks) && !permitOldBugs) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + + if (stuff->destination == PointerWindow) + pWin = sprite.win; + else if (stuff->destination == InputFocus) + { + WindowPtr inputFocus = inputInfo.keyboard->focus->win; + + if (inputFocus == NoneWin) + return Success; + + /* If the input focus is PointerRootWin, send the event to where + the pointer is if possible, then perhaps propogate up to root. */ + if (inputFocus == PointerRootWin) + inputFocus = ROOT; + + if (IsParent(inputFocus, sprite.win)) + { + effectiveFocus = inputFocus; + pWin = sprite.win; + } + else + effectiveFocus = pWin = inputFocus; + } + else + pWin = SecurityLookupWindow(stuff->destination, client, + DixReadAccess); + if (!pWin) + return BadWindow; + if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) + { + client->errorValue = stuff->propagate; + return BadValue; + } + stuff->event.u.u.type |= 0x80; + if (stuff->propagate) + { + for (;pWin; pWin = pWin->parent) + { + if (DeliverEventsToWindow(pWin, &stuff->event, 1, stuff->eventMask, + NullGrab, 0)) + return Success; + if (pWin == effectiveFocus) + return Success; + stuff->eventMask &= ~wDontPropagateMask(pWin); + if (!stuff->eventMask) + break; + } + } + else + (void)DeliverEventsToWindow(pWin, &stuff->event, 1, stuff->eventMask, + NullGrab, 0); + return Success; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXextension.c b/nx-X11/programs/Xserver/hw/nxagent/NXextension.c new file mode 100644 index 000000000..9ec6be8ef --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXextension.c @@ -0,0 +1,195 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#include "Trap.h" + +#include "../../dix/extension.c" + +int +ProcQueryExtension(ClientPtr client) +{ + xQueryExtensionReply reply; + int i; + REQUEST(xQueryExtensionReq); + + REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes); + + memset(&reply, 0, sizeof(xQueryExtensionReply)); + reply.type = X_Reply; + reply.length = 0; + reply.major_opcode = 0; + reply.sequenceNumber = client->sequence; + + if ( ! NumExtensions ) + reply.present = xFalse; + else + { + i = FindExtension((char *)&stuff[1], stuff->nbytes); + if (i < 0 + + /* + * Hide RENDER if our implementation + * is faulty. + */ + + || (nxagentRenderTrap && strcmp(extensions[i]->name, "RENDER") == 0) +#ifdef XCSECURITY + /* don't show insecure extensions to untrusted clients */ + || (client->trustLevel == XSecurityClientUntrusted && + !extensions[i]->secure) +#endif + ) + reply.present = xFalse; + else + { + reply.present = xTrue; + reply.major_opcode = extensions[i]->base; + reply.first_event = extensions[i]->eventBase; + reply.first_error = extensions[i]->errorBase; + } + } + WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply); + return(client->noClientException); +} + +int +ProcListExtensions(ClientPtr client) +{ + xListExtensionsReply reply; + char *bufptr, *buffer; + int total_length = 0; + + REQUEST_SIZE_MATCH(xReq); + + memset(&reply, 0, sizeof(xListExtensionsReply)); + reply.type = X_Reply; + reply.nExtensions = 0; + reply.length = 0; + reply.sequenceNumber = client->sequence; + buffer = NULL; + + if ( NumExtensions ) + { + register int i, j; + + for (i=0; i<NumExtensions; i++) + { +#ifdef XCSECURITY + /* don't show insecure extensions to untrusted clients */ + if (client->trustLevel == XSecurityClientUntrusted && + !extensions[i]->secure) + continue; +#endif + /* + * Hide RENDER if our implementation + * is faulty. + */ + + if (nxagentRenderTrap && strcmp(extensions[i]->name, "RENDER") == 0) + continue; + + total_length += strlen(extensions[i]->name) + 1; + reply.nExtensions += 1 + extensions[i]->num_aliases; + for (j = extensions[i]->num_aliases; --j >= 0;) + total_length += strlen(extensions[i]->aliases[j]) + 1; + } + reply.length = (total_length + 3) >> 2; + buffer = bufptr = (char *)malloc(total_length); + if (!buffer) + return(BadAlloc); + for (i=0; i<NumExtensions; i++) + { + int len; +#ifdef XCSECURITY + if (client->trustLevel == XSecurityClientUntrusted && + !extensions[i]->secure) + continue; +#endif + *bufptr++ = len = strlen(extensions[i]->name); + memmove(bufptr, extensions[i]->name, len); + bufptr += len; + for (j = extensions[i]->num_aliases; --j >= 0;) + { + *bufptr++ = len = strlen(extensions[i]->aliases[j]); + memmove(bufptr, extensions[i]->aliases[j], len); + bufptr += len; + } + } + } + WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply); + if (reply.length) + { + WriteToClient(client, total_length, buffer); + free(buffer); + } + return(client->noClientException); +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXglxext.c b/nx-X11/programs/Xserver/hw/nxagent/NXglxext.c new file mode 100644 index 000000000..5512cae1b --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXglxext.c @@ -0,0 +1,204 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* +** The contents of this file are subject to the GLX Public License Version 1.0 +** (the "License"). You may not use this file except in compliance with the +** License. You may obtain a copy of the License at Silicon Graphics, Inc., +** attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043 +** or at http://www.sgi.com/software/opensource/glx/license.html. +** +** Software distributed under the License is distributed on an "AS IS" +** basis. ALL WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY +** IMPLIED WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR +** PURPOSE OR OF NON- INFRINGEMENT. See the License for the specific +** language governing rights and limitations under the License. +** +** The Original Software is GLX version 1.2 source code, released February, +** 1999. The developer of the Original Software is Silicon Graphics, Inc. +** Those portions of the Subject Software created by Silicon Graphics, Inc. +** are Copyright (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved. +** +*/ + +#include "../../GL/glx/glxext.c" + +#include "Trap.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* +** Top level dispatcher; all commands are executed from here down. +*/ +static int __glXDispatch(ClientPtr client) +{ + int result; + + REQUEST(xGLXSingleReq); + CARD8 opcode; + int (*proc)(__GLXclientState *cl, GLbyte *pc); + __GLXclientState *cl; + + opcode = stuff->glxCode; + cl = __glXClients[client->index]; + if (!cl) { + cl = (__GLXclientState *) malloc(sizeof(__GLXclientState)); + __glXClients[client->index] = cl; + if (!cl) { + return BadAlloc; + } + memset(cl, 0, sizeof(__GLXclientState)); + } + + if (!cl->inUse) { + /* + ** This is first request from this client. Associate a resource + ** with the client so we will be notified when the client dies. + */ + XID xid = FakeClientID(client->index); + if (!AddResource( xid, __glXClientRes, (void *)(long)client->index)) { + return BadAlloc; + } + ResetClientState(client->index); + cl->inUse = GL_TRUE; + cl->client = client; + } + + /* + ** Check for valid opcode. + */ + if (opcode >= __GLX_SINGLE_TABLE_SIZE) { + return BadRequest; + } + + /* + ** If we're expecting a glXRenderLarge request, this better be one. + */ + if ((cl->largeCmdRequestsSoFar != 0) && (opcode != X_GLXRenderLarge)) { + client->errorValue = stuff->glxCode; + return __glXBadLargeRequest; + } + + /* + ** Use the opcode to index into the procedure table. + */ + proc = __glXSingleTable[opcode]; + + /* + * Report upstream that we are + * dispatching a GLX operation. + */ + + nxagentGlxTrap = 1; + + #ifdef TEST + fprintf(stderr, "__glXDispatch: Going to dispatch GLX operation [%d] for client [%d].\n", + opcode, client -> index); + #endif + + result = (*proc)(cl, (GLbyte *) stuff); + + nxagentGlxTrap = 0; + + #ifdef TEST + fprintf(stderr, "__glXDispatch: Dispatched GLX operation [%d] for client [%d].\n", + opcode, client -> index); + #endif + + return result; +} + +static int __glXSwapDispatch(ClientPtr client) +{ + int result; + + REQUEST(xGLXSingleReq); + CARD8 opcode; + int (*proc)(__GLXclientState *cl, GLbyte *pc); + __GLXclientState *cl; + + opcode = stuff->glxCode; + cl = __glXClients[client->index]; + if (!cl) { + cl = (__GLXclientState *) malloc(sizeof(__GLXclientState)); + __glXClients[client->index] = cl; + if (!cl) { + return BadAlloc; + } + memset(cl, 0, sizeof(__GLXclientState)); + } + + if (!cl->inUse) { + /* + ** This is first request from this client. Associate a resource + ** with the client so we will be notified when the client dies. + */ + XID xid = FakeClientID(client->index); + if (!AddResource( xid, __glXClientRes, (void *)(long)client->index)) { + return BadAlloc; + } + ResetClientState(client->index); + cl->inUse = GL_TRUE; + cl->client = client; + } + + /* + ** Check for valid opcode. + */ + if (opcode >= __GLX_SINGLE_TABLE_SIZE) { + return BadRequest; + } + + /* + ** Use the opcode to index into the procedure table. + */ + proc = __glXSwapSingleTable[opcode]; + + /* + * Report upstream that we are + * dispatching a GLX operation. + */ + + nxagentGlxTrap = 1; + + #ifdef TEST + fprintf(stderr, "__glXDispatch: Going to dispatch GLX operation [%d] for client [%d].\n", + opcode, client -> index); + #endif + + result = (*proc)(cl, (GLbyte *) stuff); + + nxagentGlxTrap = 0; + + #ifdef TEST + fprintf(stderr, "__glXDispatch: Dispatched GLX operation [%d] for client [%d].\n", + opcode, client -> index); + #endif + + return result; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXglyph.c b/nx-X11/programs/Xserver/hw/nxagent/NXglyph.c new file mode 100644 index 000000000..35dcbc132 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXglyph.c @@ -0,0 +1,381 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Keith Packard, SuSE, Inc. + */ + +#include "../../render/glyph.c" + +#ifdef NXAGENT_SERVER + +#include "Render.h" + +#define PANIC +#define WARNING +#undef DEBUG +#undef TEST + +#endif + +void +AddGlyph (GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id) +{ + GlyphRefPtr gr; + CARD32 hash; + + CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph top global"); + /* Locate existing matching glyph */ + hash = HashGlyph (glyph); + gr = FindGlyphRef (&globalGlyphs[glyphSet->fdepth], hash, TRUE, glyph); + if (gr->glyph && gr->glyph != DeletedGlyph) + { + free (glyph); + glyph = gr->glyph; + } + else + { + gr->glyph = glyph; + gr->signature = hash; + globalGlyphs[glyphSet->fdepth].tableEntries++; + } + + /* Insert/replace glyphset value */ + gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0); + ++glyph->refcnt; + if (gr->glyph && gr->glyph != DeletedGlyph) + FreeGlyph (gr->glyph, glyphSet->fdepth); + else + glyphSet->hash.tableEntries++; + gr->glyph = glyph; + gr->signature = id; + + #ifdef NXAGENT_SERVER + + gr -> corruptedGlyph = 1; + + #endif + + CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom"); +} + +GlyphPtr FindGlyph (GlyphSetPtr glyphSet, Glyph id) +{ + GlyphRefPtr gr; + GlyphPtr glyph; + + gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0); + glyph = gr -> glyph; + + if (glyph == DeletedGlyph) + { + glyph = 0; + } + else if (gr -> corruptedGlyph == 1) + { + #ifdef DEBUG + fprintf(stderr, "FindGlyphRef: Going to synchronize the glyph [%p] for glyphset [%p].\n", + (void *) glyph, (void *) glyphSet); + #endif + + nxagentAddGlyphs(glyphSet, &id, &(glyph -> info), 1, + (CARD8*)(glyph + 1), glyph -> size - sizeof(xGlyphInfo)); + } + + return glyph; +} + +Bool +ResizeGlyphHash (GlyphHashPtr hash, CARD32 change, Bool global) +{ + CARD32 tableEntries; + GlyphHashSetPtr hashSet; + GlyphHashRec newHash; + GlyphRefPtr gr; + GlyphPtr glyph; + int i; + int oldSize; + CARD32 s; + + #ifdef NXAGENT_SERVER + + CARD32 c; + + #endif + + tableEntries = hash->tableEntries + change; + hashSet = FindGlyphHashSet (tableEntries); + if (hashSet == hash->hashSet) + return TRUE; + if (global) + CheckDuplicates (hash, "ResizeGlyphHash top"); + if (!AllocateGlyphHash (&newHash, hashSet)) + return FALSE; + if (hash->table) + { + oldSize = hash->hashSet->size; + for (i = 0; i < oldSize; i++) + { + glyph = hash->table[i].glyph; + if (glyph && glyph != DeletedGlyph) + { + s = hash->table[i].signature; + + #ifdef NXAGENT_SERVER + + c = hash->table[i].corruptedGlyph; + + #endif + + gr = FindGlyphRef (&newHash, s, global, glyph); + gr->signature = s; + gr->glyph = glyph; + + #ifdef NXAGENT_SERVER + + gr -> corruptedGlyph = c; + + #endif + + ++newHash.tableEntries; + } + } + free (hash->table); + } + *hash = newHash; + if (global) + CheckDuplicates (hash, "ResizeGlyphHash bottom"); + return TRUE; +} + +void +miGlyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ + PixmapPtr pPixmap = 0; + PicturePtr pPicture; + PixmapPtr pMaskPixmap = 0; + PicturePtr pMask; + ScreenPtr pScreen = pDst->pDrawable->pScreen; + int width = 0, height = 0; + int x, y; + int xDst = list->xOff, yDst = list->yOff; + int n; + GlyphPtr glyph; + int error; + BoxRec extents; + CARD32 component_alpha; + + /* + * Get rid of the warning. + */ + + extents.x1 = 0; + extents.y1 = 0; + + if (maskFormat) + { + GCPtr pGC; + xRectangle rect; + + if (nxagentGlyphsExtents != NullBox) + { + memcpy(&extents, nxagentGlyphsExtents, sizeof(BoxRec)); + } + else + { + nxagentGlyphsExtents = (BoxPtr) malloc(sizeof(BoxRec)); + + GlyphExtents (nlist, list, glyphs, &extents); + + memcpy(nxagentGlyphsExtents, &extents, sizeof(BoxRec)); + } + + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + + if (!pMaskPixmap) + return; + + component_alpha = NeedsComponent(maskFormat->format); + pMask = CreatePicture (0, &pMaskPixmap->drawable, + maskFormat, CPComponentAlpha, &component_alpha, + serverClient, &error); + + if (!pMask) + { + (*pScreen->DestroyPixmap) (pMaskPixmap); + return; + } + pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); + ValidateGC (&pMaskPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); + FreeScratchGC (pGC); + x = -extents.x1; + y = -extents.y1; + } + else + { + pMask = pDst; + x = 0; + y = 0; + } + pPicture = 0; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + + while (n--) + { + glyph = *glyphs++; + if (!pPicture) + { + pPixmap = GetScratchPixmapHeader (pScreen, glyph->info.width, glyph->info.height, + list->format->depth, + list->format->depth, + 0, (void *) (glyph + 1)); + if (!pPixmap) + return; + component_alpha = NeedsComponent(list->format->format); + pPicture = CreatePicture (0, &pPixmap->drawable, list->format, + CPComponentAlpha, &component_alpha, + serverClient, &error); + if (!pPicture) + { + FreeScratchPixmapHeader (pPixmap); + return; + } + } + (*pScreen->ModifyPixmapHeader) (pPixmap, + glyph->info.width, glyph->info.height, + 0, 0, -1, (void *) (glyph + 1)); + + /* + * The following line fixes a problem with glyphs that appeared + * as clipped. It was a side effect due the validate function + * "ValidatePicture" that makes a check on the Drawable serial + * number instead of the picture serial number, failing thus + * the clip mask update. + */ + + pPicture->pDrawable->serialNumber = NEXT_SERIAL_NUMBER; + + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + if (maskFormat) + { + CompositePicture (PictOpAdd, + pPicture, + None, + pMask, + 0, 0, + 0, 0, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + } + else + { + CompositePicture (op, + pSrc, + pPicture, + pDst, + xSrc + (x - glyph->info.x) - xDst, + ySrc + (y - glyph->info.y) - yDst, + 0, 0, + x - glyph->info.x, + y - glyph->info.y, + glyph->info.width, + glyph->info.height); + } + x += glyph->info.xOff; + y += glyph->info.yOff; + } + + list++; + if (pPicture) + { + FreeScratchPixmapHeader (pPixmap); + FreePicture ((void *) pPicture, 0); + pPicture = 0; + pPixmap = 0; + } + } + if (maskFormat) + { + x = extents.x1; + y = extents.y1; + CompositePicture (op, + pSrc, + pMask, + pDst, + xSrc + x - xDst, + ySrc + y - yDst, + 0, 0, + x, y, + width, height); + + FreePicture ((void *) pMask, (XID) 0); + (*pScreen->DestroyPixmap) (pMaskPixmap); + } + +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXglyphcurs.c b/nx-X11/programs/Xserver/hw/nxagent/NXglyphcurs.c new file mode 100644 index 000000000..549ab4333 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXglyphcurs.c @@ -0,0 +1,180 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/************************************************************************ + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +************************************************************************/ + + +#include "../../dix/glyphcurs.c" + +#include "../../fb/fb.h" +#include "Pixmaps.h" + +#ifndef True +#define True 1 +#endif + +/* + get the bits out of the font in a portable way. to avoid +dealing with padding and such-like, we draw the glyph into +a bitmap, then read the bits out with GetImage, which +uses server-natural format. + since all screens return the same bitmap format, we'll just use +the first one we find. + the character origin lines up with the hotspot in the +cursor metrics. +*/ + +int +ServerBitsFromGlyph(FontPtr pfont, unsigned ch, register CursorMetricPtr cm, unsigned char **ppbits) +{ + register ScreenPtr pScreen; + register GCPtr pGC; + xRectangle rect; + PixmapPtr ppix; + long nby; + char *pbits; + unsigned char char2b[2]; + + /* turn glyph index into a protocol-format char2b */ + char2b[0] = (unsigned char)(ch >> 8); + char2b[1] = (unsigned char)(ch & 0xff); + + pScreen = screenInfo.screens[0]; + nby = BitmapBytePad(cm->width) * (long)cm->height; + pbits = (char *)malloc(nby); + if (!pbits) + return BadAlloc; + /* zeroing the (pad) bits seems to help some ddx cursor handling */ + bzero(pbits, nby); + + ppix = fbCreatePixmap(pScreen, cm->width, cm->height, 1, + CREATE_PIXMAP_USAGE_SCRATCH); + pGC = GetScratchGC(1, pScreen); + if (!ppix || !pGC) + { + if (ppix) + fbDestroyPixmap(ppix); + if (pGC) + FreeScratchGC(pGC); + free(pbits); + return BadAlloc; + } + + #ifdef TEST + fprintf(stderr, "ServerBitsFromGlyph: Created virtual pixmap at [%p] with width [%d] height [%d] depth [%d].\n", + (void *) ppix, cm->width, cm->height, 1); + #endif + + nxagentPixmapPriv(ppix) -> id = 0; + nxagentPixmapPriv(ppix) -> mid = 0; + nxagentPixmapPriv(ppix) -> isVirtual = True; + nxagentPixmapPriv(ppix) -> pRealPixmap = NULL; + nxagentPixmapPriv(ppix) -> pVirtualPixmap = NULL; + + rect.x = 0; + rect.y = 0; + rect.width = cm->width; + rect.height = cm->height; + + pGC->stateChanges |= GCFunction | GCForeground | GCFont; + pGC->alu = GXcopy; + + pGC->fgPixel = 0; + + pfont->refcnt++; + + if (pGC->font) + CloseFont(pGC->font, (Font)0); + + pGC->font = pfont; + + ValidateGC((DrawablePtr)ppix, pGC); + fbPolyFillRect((DrawablePtr)ppix, pGC, 1, &rect); + + /* draw the glyph */ + pGC->fgPixel = 1; + + pGC->stateChanges |= GCForeground; + + ValidateGC((DrawablePtr)ppix, pGC); + miPolyText16((DrawablePtr)ppix, pGC, (int)cm->xhot, (int)cm->yhot, (int)1, (unsigned short*)char2b); + fbGetImage((DrawablePtr)ppix, 0, 0, cm->width, cm->height, + XYPixmap, 1, pbits); + *ppbits = (unsigned char *)pbits; + FreeScratchGC(pGC); + fbDestroyPixmap(ppix); + + #ifdef TEST + fprintf(stderr, "ServerBitsFromGlyph: Destroyed virtual pixmap at [%p].\n", + (void *) ppix); + #endif + + return Success; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXglyphstr_GlyphRef.h b/nx-X11/programs/Xserver/hw/nxagent/NXglyphstr_GlyphRef.h new file mode 100644 index 000000000..eef2da8dd --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXglyphstr_GlyphRef.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) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Keith Packard, SuSE, Inc. + */ + +/* this header file gets included into Xserver/render/glyphstr.h */ + +#ifndef NX_GLYPHSTR_GLYPHREF_H +#define NX_GLYPHSTR_GLYPHREF_H 1 + +typedef struct _GlyphRef { + CARD32 signature; + GlyphPtr glyph; + CARD16 corruptedGlyph; +} GlyphRefRec, *GlyphRefPtr; + +#endif /* NX_GLYPHSTR_GLYPHREF_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXglyphstr_GlyphSet.h b/nx-X11/programs/Xserver/hw/nxagent/NXglyphstr_GlyphSet.h new file mode 100644 index 000000000..98f331dd7 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXglyphstr_GlyphSet.h @@ -0,0 +1,64 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Keith Packard, SuSE, Inc. + */ + +/* this header file gets included into Xserver/render/glyphstr.h */ + +#ifndef NX_GLYPHSTR_GLYPHSET_H +#define NX_GLYPHSTR_GLYPHSET_H 1 + +typedef struct _GlyphSet { + CARD32 refcnt; + PictFormatPtr format; + int fdepth; + GlyphHashRec hash; + int maxPrivate; + void **devPrivates; + CARD32 remoteID; +} GlyphSetRec, *GlyphSetPtr; + +#endif /* NX_GLYPHSTR_GLYPHSET_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXmiexpose.c b/nx-X11/programs/Xserver/hw/nxagent/NXmiexpose.c new file mode 100644 index 000000000..bcb88d42d --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXmiexpose.c @@ -0,0 +1,743 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + + +#include "Windows.h" + +#include "../../mi/miexpose.c" + +/* miHandleExposures + generate a region for exposures for areas that were copied from obscured or +non-existent areas to non-obscured areas of the destination. Paint the +background for the region, if the destination is a window. + +NOTE: + this should generally be called, even if graphicsExposures is false, +because this is where bits get recovered from backing store. + +NOTE: + added argument 'plane' is used to indicate how exposures from backing +store should be accomplished. If plane is 0 (i.e. no bit plane), CopyArea +should be used, else a CopyPlane of the indicated plane will be used. The +exposing is done by the backing store's GraphicsExpose function, of course. + +*/ + +RegionPtr +miHandleExposures(pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, width, height, dstx, dsty, plane) + register DrawablePtr pSrcDrawable; + register DrawablePtr pDstDrawable; + GCPtr pGC; + int srcx, srcy; + int width, height; + int dstx, dsty; + unsigned long plane; +{ + register ScreenPtr pscr; + RegionPtr prgnSrcClip; /* drawable-relative source clip */ + RegionRec rgnSrcRec; + RegionPtr prgnDstClip; /* drawable-relative dest clip */ + RegionRec rgnDstRec; + BoxRec srcBox; /* unclipped source */ + RegionRec rgnExposed; /* exposed region, calculated source- + relative, made dst relative to + intersect with visible parts of + dest and send events to client, + and then screen relative to paint + the window background + */ + WindowPtr pSrcWin; + BoxRec expBox; + Bool extents; + + /* + * Set the elements reported by the compiler + * as uninitialized. + */ + + expBox.x1 = 0; + expBox.y1 = 0; + expBox.x2 = 0; + expBox.y2 = 0; + + /* This prevents warning about pscr not being used. */ + pGC->pScreen = pscr = pGC->pScreen; + + /* avoid work if we can */ + if (!pGC->graphicsExposures && + (pDstDrawable->type == DRAWABLE_PIXMAP) && + ((pSrcDrawable->type == DRAWABLE_PIXMAP) || + (((WindowPtr)pSrcDrawable)->backStorage == NULL))) + return NULL; + + srcBox.x1 = srcx; + srcBox.y1 = srcy; + srcBox.x2 = srcx+width; + srcBox.y2 = srcy+height; + + if (pSrcDrawable->type != DRAWABLE_PIXMAP) + { + BoxRec TsrcBox; + + TsrcBox.x1 = srcx + pSrcDrawable->x; + TsrcBox.y1 = srcy + pSrcDrawable->y; + TsrcBox.x2 = TsrcBox.x1 + width; + TsrcBox.y2 = TsrcBox.y1 + height; + pSrcWin = (WindowPtr) pSrcDrawable; + if (pGC->subWindowMode == IncludeInferiors) + { + prgnSrcClip = NotClippedByChildren (pSrcWin); + if ((RegionContainsRect(prgnSrcClip, &TsrcBox)) == rgnIN) + { + RegionDestroy(prgnSrcClip); + return NULL; + } + } + else + { + if ((RegionContainsRect(&pSrcWin->clipList, &TsrcBox)) == rgnIN) + return NULL; + prgnSrcClip = &rgnSrcRec; + RegionNull(prgnSrcClip); + RegionCopy(prgnSrcClip, &pSrcWin->clipList); + } + RegionTranslate(prgnSrcClip, + -pSrcDrawable->x, -pSrcDrawable->y); + } + else + { + BoxRec box; + + if ((srcBox.x1 >= 0) && (srcBox.y1 >= 0) && + (srcBox.x2 <= pSrcDrawable->width) && + (srcBox.y2 <= pSrcDrawable->height)) + return NULL; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pSrcDrawable->width; + box.y2 = pSrcDrawable->height; + prgnSrcClip = &rgnSrcRec; + RegionInit(prgnSrcClip, &box, 1); + pSrcWin = (WindowPtr)NULL; + } + + if (pDstDrawable == pSrcDrawable) + { + prgnDstClip = prgnSrcClip; + } + else if (pDstDrawable->type != DRAWABLE_PIXMAP) + { + if (pGC->subWindowMode == IncludeInferiors) + { + prgnDstClip = NotClippedByChildren((WindowPtr)pDstDrawable); + } + else + { + prgnDstClip = &rgnDstRec; + RegionNull(prgnDstClip); + RegionCopy(prgnDstClip, + &((WindowPtr)pDstDrawable)->clipList); + } + RegionTranslate(prgnDstClip, + -pDstDrawable->x, -pDstDrawable->y); + } + else + { + BoxRec box; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pDstDrawable->width; + box.y2 = pDstDrawable->height; + prgnDstClip = &rgnDstRec; + RegionInit(prgnDstClip, &box, 1); + } + + /* drawable-relative source region */ + RegionInit(&rgnExposed, &srcBox, 1); + + /* now get the hidden parts of the source box*/ + RegionSubtract(&rgnExposed, &rgnExposed, prgnSrcClip); + + if (pSrcWin && pSrcWin->backStorage) + { + /* + * Copy any areas from the source backing store. Modifies + * rgnExposed. + */ + (* pSrcWin->drawable.pScreen->ExposeCopy) ((WindowPtr)pSrcDrawable, + pDstDrawable, + pGC, + &rgnExposed, + srcx, srcy, + dstx, dsty, + plane); + } + + /* move them over the destination */ + RegionTranslate(&rgnExposed, dstx-srcx, dsty-srcy); + + /* intersect with visible areas of dest */ + RegionIntersect(&rgnExposed, &rgnExposed, prgnDstClip); + + /* + * If we have LOTS of rectangles, we decide to take the extents + * and force an exposure on that. This should require much less + * work overall, on both client and server. This is cheating, but + * isn't prohibited by the protocol ("spontaneous combustion" :-) + * for windows. + */ + extents = pGC->graphicsExposures && + (RegionNumRects(&rgnExposed) > RECTLIMIT) && + (pDstDrawable->type != DRAWABLE_PIXMAP); +#ifdef SHAPE + if (pSrcWin) + { + RegionPtr region; + if (!(region = wClipShape (pSrcWin))) + region = wBoundingShape (pSrcWin); + /* + * If you try to CopyArea the extents of a shaped window, compacting the + * exposed region will undo all our work! + */ + if (extents && pSrcWin && region && + (RegionContainsRect(region, &srcBox) != rgnIN)) + extents = FALSE; + } +#endif + if (extents) + { + WindowPtr pWin = (WindowPtr)pDstDrawable; + + expBox = *RegionExtents(&rgnExposed); + RegionReset(&rgnExposed, &expBox); + /* need to clear out new areas of backing store */ + if (pWin->backStorage) + (void) (* pWin->drawable.pScreen->ClearBackingStore)( + pWin, + expBox.x1, + expBox.y1, + expBox.x2 - expBox.x1, + expBox.y2 - expBox.y1, + FALSE); + } + if ((pDstDrawable->type != DRAWABLE_PIXMAP) && + (((WindowPtr)pDstDrawable)->backgroundState != None)) + { + WindowPtr pWin = (WindowPtr)pDstDrawable; + + /* make the exposed area screen-relative */ + RegionTranslate(&rgnExposed, + pDstDrawable->x, pDstDrawable->y); + + if (extents) + { + /* PaintWindowBackground doesn't clip, so we have to */ + RegionIntersect(&rgnExposed, &rgnExposed, &pWin->clipList); + } + (*pWin->drawable.pScreen->PaintWindowBackground)( + (WindowPtr)pDstDrawable, &rgnExposed, PW_BACKGROUND); + + if (extents) + { + RegionReset(&rgnExposed, &expBox); + } + else + RegionTranslate(&rgnExposed, + -pDstDrawable->x, -pDstDrawable->y); + } + if (prgnDstClip == &rgnDstRec) + { + RegionUninit(prgnDstClip); + } + else if (prgnDstClip != prgnSrcClip) + { + RegionDestroy(prgnDstClip); + } + + if (prgnSrcClip == &rgnSrcRec) + { + RegionUninit(prgnSrcClip); + } + else + { + RegionDestroy(prgnSrcClip); + } + + if (pGC->graphicsExposures) + { + /* don't look */ + RegionPtr exposed = RegionCreate(NullBox, 0); + *exposed = rgnExposed; + return exposed; + } + else + { + RegionUninit(&rgnExposed); + return NULL; + } +} + +void +miWindowExposures(pWin, prgn, other_exposed) + WindowPtr pWin; + register RegionPtr prgn, other_exposed; +{ + + int total; + + RegionPtr exposures = prgn; + if (pWin->backStorage && prgn) + /* + * in some cases, backing store will cause a different + * region to be exposed than needs to be repainted + * (like when a window is mapped). RestoreAreas is + * allowed to return a region other than prgn, + * in which case this routine will free the resultant + * region. If exposures is null, then no events will + * be sent to the client; if prgn is empty + * no areas will be repainted. + */ + exposures = (*pWin->drawable.pScreen->RestoreAreas)(pWin, prgn); + if ((prgn && !RegionNil(prgn)) || + (exposures && !RegionNil(exposures)) || other_exposed) + { + RegionRec expRec; + int clientInterested; + + /* + * Restore from backing-store FIRST. + */ + clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & ExposureMask; + if (other_exposed) + { + if (exposures) + { + RegionUnion(other_exposed, + exposures, + other_exposed); + if (exposures != prgn) + RegionDestroy(exposures); + } + exposures = other_exposed; + } + + /* + * If the number of rectangles is greater + * than 4, let the function decide. + */ + + total = RegionNumRects(exposures); + + if (clientInterested && exposures && (total > RECTLIMIT || + (total > 4 && nxagentExtentsPredicate(total) == 1))) + { + /* + * If we have LOTS of rectangles, we decide to take the extents + * and force an exposure on that. This should require much less + * work overall, on both client and server. This is cheating, but + * isn't prohibited by the protocol ("spontaneous combustion" :-). + */ + BoxRec box; + + box = *RegionExtents(exposures); + if (exposures == prgn) { + exposures = &expRec; + RegionInit(exposures, &box, 1); + RegionReset(prgn, &box); + } else { + RegionReset(exposures, &box); + RegionUnion(prgn, prgn, exposures); + } + /* PaintWindowBackground doesn't clip, so we have to */ + RegionIntersect(prgn, prgn, &pWin->clipList); + /* need to clear out new areas of backing store, too */ + if (pWin->backStorage) + (void) (* pWin->drawable.pScreen->ClearBackingStore)( + pWin, + box.x1 - pWin->drawable.x, + box.y1 - pWin->drawable.y, + box.x2 - box.x1, + box.y2 - box.y1, + FALSE); + } + if (prgn && !RegionNil(prgn)) + (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, prgn, PW_BACKGROUND); + if (clientInterested && exposures && !RegionNil(exposures)) + miSendExposures(pWin, exposures, + pWin->drawable.x, pWin->drawable.y); + if (exposures == &expRec) + { + RegionUninit(exposures); + } + else if (exposures && exposures != prgn && exposures != other_exposed) + RegionDestroy(exposures); + if (prgn) + RegionEmpty(prgn); + } + else if (exposures && exposures != prgn) + RegionDestroy(exposures); +} + +void +miPaintWindow(pWin, prgn, what) +register WindowPtr pWin; +RegionPtr prgn; +int what; +{ + int status; + + Bool usingScratchGC = FALSE; + WindowPtr pRoot; + +#define FUNCTION 0 +#define FOREGROUND 1 +#define TILE 2 +#define FILLSTYLE 3 +#define ABSX 4 +#define ABSY 5 +#define CLIPMASK 6 +#define SUBWINDOW 7 +#define COUNT_BITS 8 + + ChangeGCVal gcval[7]; + ChangeGCVal newValues [COUNT_BITS] = {{ 0 }}; + + BITS32 gcmask, index, mask; + RegionRec prgnWin; + DDXPointRec oldCorner; + BoxRec box; + WindowPtr pBgWin; + GCPtr pGC; + register int i; + register BoxPtr pbox; + register ScreenPtr pScreen = pWin->drawable.pScreen; + register xRectangle *prect; + int numRects; + + /* + * Set the elements reported by the compiler + * as uninitialized. + */ + + prgnWin.extents.x1 = 0; + prgnWin.extents.y1 = 0; + prgnWin.extents.x2 = 0; + prgnWin.extents.y2 = 0; + + prgnWin.data = NULL; + + oldCorner.x = 0; + oldCorner.y = 0; + + gcmask = 0; + + if (what == PW_BACKGROUND) + { + switch (pWin->backgroundState) { + case None: + return; + case ParentRelative: + (*pWin->parent->drawable.pScreen->PaintWindowBackground)(pWin->parent, prgn, what); + return; + case BackgroundPixel: + newValues[FOREGROUND].val = pWin->background.pixel; + newValues[FILLSTYLE].val = FillSolid; + gcmask |= GCForeground | GCFillStyle; + break; + case BackgroundPixmap: + newValues[TILE].ptr = (void *)pWin->background.pixmap; + newValues[FILLSTYLE].val = FillTiled; + gcmask |= GCTile | GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin; + break; + } + } + else + { + if (pWin->borderIsPixel) + { + newValues[FOREGROUND].val = pWin->border.pixel; + newValues[FILLSTYLE].val = FillSolid; + gcmask |= GCForeground | GCFillStyle; + } + else + { + newValues[TILE].ptr = (void *)pWin->border.pixmap; + newValues[FILLSTYLE].val = FillTiled; + gcmask |= GCTile | GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin; + } + } + + prect = (xRectangle *)malloc(RegionNumRects(prgn) * + sizeof(xRectangle)); + if (!prect) + return; + + newValues[FUNCTION].val = GXcopy; + gcmask |= GCFunction | GCClipMask; + + i = pScreen->myNum; + pRoot = screenInfo.screens[i]->root; + + pBgWin = pWin; + if (what == PW_BORDER) + { + while (pBgWin->backgroundState == ParentRelative) + pBgWin = pBgWin->parent; + } + + if ((pWin->drawable.depth != pRoot->drawable.depth) || + (pWin->drawable.bitsPerPixel != pRoot->drawable.bitsPerPixel)) + { + usingScratchGC = TRUE; + pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen); + if (!pGC) + { + free(prect); + return; + } + /* + * mash the clip list so we can paint the border by + * mangling the window in place, pretending it + * spans the entire screen + */ + if (what == PW_BORDER) + { + prgnWin = pWin->clipList; + oldCorner.x = pWin->drawable.x; + oldCorner.y = pWin->drawable.y; + pWin->drawable.x = pWin->drawable.y = 0; + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + RegionInit(&pWin->clipList, &box, 1); + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + newValues[ABSX].val = pBgWin->drawable.x; + newValues[ABSY].val = pBgWin->drawable.y; + } + else + { + newValues[ABSX].val = 0; + newValues[ABSY].val = 0; + } + } else { + /* + * draw the background to the root window + */ + if (screenContext[i] == (GCPtr)NULL) + { + if (!ResType && !(ResType = CreateNewResourceType(tossGC))) + return; + screenContext[i] = CreateGC((DrawablePtr)pWin, (BITS32) 0, + (XID *)NULL, &status); + if (!screenContext[i]) + return; + numGCs++; + if (!AddResource(FakeClientID(0), ResType, + (void *)screenContext[i])) + return; + } + pGC = screenContext[i]; + newValues[SUBWINDOW].val = IncludeInferiors; + newValues[ABSX].val = pBgWin->drawable.x; + newValues[ABSY].val = pBgWin->drawable.y; + gcmask |= GCSubwindowMode; + pWin = pRoot; + } + + if (pWin->backStorage) + (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack); + + mask = gcmask; + gcmask = 0; + i = 0; + while (mask) { + index = lowbit (mask); + mask &= ~index; + switch (index) { + case GCFunction: + if (pGC->alu != newValues[FUNCTION].val) { + gcmask |= index; + gcval[i++].val = newValues[FUNCTION].val; + } + break; + case GCTileStipXOrigin: + if ( pGC->patOrg.x != newValues[ABSX].val) { + gcmask |= index; + gcval[i++].val = newValues[ABSX].val; + } + break; + case GCTileStipYOrigin: + if ( pGC->patOrg.y != newValues[ABSY].val) { + gcmask |= index; + gcval[i++].val = newValues[ABSY].val; + } + break; + case GCClipMask: + if ( pGC->clientClipType != CT_NONE) { + gcmask |= index; + gcval[i++].val = CT_NONE; + } + break; + case GCSubwindowMode: + if ( pGC->subWindowMode != newValues[SUBWINDOW].val) { + gcmask |= index; + gcval[i++].val = newValues[SUBWINDOW].val; + } + break; + case GCTile: + if (pGC->tileIsPixel || pGC->tile.pixmap != newValues[TILE].ptr) + { + gcmask |= index; + gcval[i++].ptr = newValues[TILE].ptr; + } + break; + case GCFillStyle: + if ( pGC->fillStyle != newValues[FILLSTYLE].val) { + gcmask |= index; + gcval[i++].val = newValues[FILLSTYLE].val; + } + break; + case GCForeground: + if ( pGC->fgPixel != newValues[FOREGROUND].val) { + gcmask |= index; + gcval[i++].val = newValues[FOREGROUND].val; + } + break; + } + } + + if (gcmask) + dixChangeGC(NullClient, pGC, gcmask, NULL, gcval); + + if (pWin->drawable.serialNumber != pGC->serialNumber) + ValidateGC((DrawablePtr)pWin, pGC); + + numRects = RegionNumRects(prgn); + pbox = RegionRects(prgn); + for (i= numRects; --i >= 0; pbox++, prect++) + { + prect->x = pbox->x1 - pWin->drawable.x; + prect->y = pbox->y1 - pWin->drawable.y; + prect->width = pbox->x2 - pbox->x1; + prect->height = pbox->y2 - pbox->y1; + } + prect -= numRects; + (*pGC->ops->PolyFillRect)((DrawablePtr)pWin, pGC, numRects, prect); + free(prect); + + if (pWin->backStorage) + (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeNothing); + + if (usingScratchGC) + { + if (what == PW_BORDER) + { + RegionUninit(&pWin->clipList); + pWin->clipList = prgnWin; + pWin->drawable.x = oldCorner.x; + pWin->drawable.y = oldCorner.y; + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } + FreeScratchGC(pGC); + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXmitrap.c b/nx-X11/programs/Xserver/hw/nxagent/NXmitrap.c new file mode 100644 index 000000000..1988ca102 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXmitrap.c @@ -0,0 +1,123 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "Render.h" + +#include "../../render/mitrap.c" + +void +miTrapezoids (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int ntrap, + xTrapezoid *traps) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + + /* + * Check for solid alpha add + */ + if (op == PictOpAdd && miIsSolidAlpha (pSrc)) + { + for (; ntrap; ntrap--, traps++) + (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0); + } + else if (maskFormat) + { + PicturePtr pPicture; + BoxRec bounds; + INT16 xDst, yDst; + INT16 xRel, yRel; + + xDst = traps[0].left.p1.x >> 16; + yDst = traps[0].left.p1.y >> 16; + + if (nxagentTrapezoidExtents != NullBox) + { + memcpy(&bounds, nxagentTrapezoidExtents, sizeof(BoxRec)); + } + else + { + nxagentTrapezoidExtents = (BoxPtr) malloc(sizeof(BoxRec)); + + miTrapezoidBounds (ntrap, traps, &bounds); + + memcpy(nxagentTrapezoidExtents, &bounds, sizeof(BoxRec)); + } + + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + pPicture = miCreateAlphaPicture (pScreen, pDst, maskFormat, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!pPicture) + return; + for (; ntrap; ntrap--, traps++) + (*ps->RasterizeTrapezoid) (pPicture, traps, + -bounds.x1, -bounds.y1); + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture (op, pSrc, pPicture, pDst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + FreePicture (pPicture, 0); + } + else + { + if (pDst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + for (; ntrap; ntrap--, traps++) + miTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXpicture.c b/nx-X11/programs/Xserver/hw/nxagent/NXpicture.c new file mode 100644 index 000000000..4ea7d2d73 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXpicture.c @@ -0,0 +1,654 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Keith Packard, SuSE, Inc. + */ + +#include "picturestr.h" + +#include "Screen.h" +#include "Pixmaps.h" +#include "Drawable.h" +#include "Render.h" + +/* prototypes */ + +PictFormatPtr PictureCreateDefaultFormats (ScreenPtr pScreen, int *nformatp); +PicturePtr AllocatePicture (ScreenPtr pScreen); +PicturePtr CreatePicture (Picture pid, + DrawablePtr pDrawable, + PictFormatPtr pFormat, + Mask vmask, + XID *vlist, + ClientPtr client, + int *error); +static PicturePtr createSourcePicture(void); +int FreePicture (void *value, XID pid); + +#include "../../render/picture.c" + + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +void *nxagentVisualFromID(ScreenPtr pScreen, VisualID visual); + +void *nxagentMatchingFormats(PictFormatPtr pForm); + +void nxagentPictureCreateDefaultFormats(ScreenPtr pScreen, FormatInitRec *formats, int *nformats); + +PictFormatPtr +PictureCreateDefaultFormats (ScreenPtr pScreen, int *nformatp) +{ + int nformats, f; + PictFormatPtr pFormats; + FormatInitRec formats[1024]; + CARD32 format; + + nformats = 0; + + nxagentPictureCreateDefaultFormats(pScreen, formats, &nformats); + + pFormats = (PictFormatPtr) calloc (nformats, sizeof (PictFormatRec)); + if (!pFormats) + return 0; + for (f = 0; f < nformats; f++) + { + pFormats[f].id = FakeClientID (0); + pFormats[f].depth = formats[f].depth; + format = formats[f].format; + pFormats[f].format = format; + switch (PICT_FORMAT_TYPE(format)) { + case PICT_TYPE_ARGB: + pFormats[f].type = PictTypeDirect; + + pFormats[f].direct.alphaMask = Mask(PICT_FORMAT_A(format)); + if (pFormats[f].direct.alphaMask) + pFormats[f].direct.alpha = (PICT_FORMAT_R(format) + + PICT_FORMAT_G(format) + + PICT_FORMAT_B(format)); + + pFormats[f].direct.redMask = Mask(PICT_FORMAT_R(format)); + pFormats[f].direct.red = (PICT_FORMAT_G(format) + + PICT_FORMAT_B(format)); + + pFormats[f].direct.greenMask = Mask(PICT_FORMAT_G(format)); + pFormats[f].direct.green = PICT_FORMAT_B(format); + + pFormats[f].direct.blueMask = Mask(PICT_FORMAT_B(format)); + pFormats[f].direct.blue = 0; + break; + + case PICT_TYPE_ABGR: + pFormats[f].type = PictTypeDirect; + + pFormats[f].direct.alphaMask = Mask(PICT_FORMAT_A(format)); + if (pFormats[f].direct.alphaMask) + pFormats[f].direct.alpha = (PICT_FORMAT_B(format) + + PICT_FORMAT_G(format) + + PICT_FORMAT_R(format)); + + pFormats[f].direct.blueMask = Mask(PICT_FORMAT_B(format)); + pFormats[f].direct.blue = (PICT_FORMAT_G(format) + + PICT_FORMAT_R(format)); + + pFormats[f].direct.greenMask = Mask(PICT_FORMAT_G(format)); + pFormats[f].direct.green = PICT_FORMAT_R(format); + + pFormats[f].direct.redMask = Mask(PICT_FORMAT_R(format)); + pFormats[f].direct.red = 0; + break; + + case PICT_TYPE_A: + pFormats[f].type = PictTypeDirect; + + pFormats[f].direct.alpha = 0; + pFormats[f].direct.alphaMask = Mask(PICT_FORMAT_A(format)); + + /* remaining fields already set to zero */ + break; + + case PICT_TYPE_COLOR: + case PICT_TYPE_GRAY: + pFormats[f].type = PictTypeIndexed; + pFormats[f].index.vid = pScreen->visuals[PICT_FORMAT_VIS(format)].vid; + break; + } + + if (nxagentMatchingFormats(&pFormats[f]) != NULL) + { + #ifdef DEBUG + fprintf(stderr, "PictureCreateDefaultFormats: Format with type [%d] depth [%d] rgb [%d,%d,%d] " + "mask rgb [%d,%d,%d] alpha [%d] alpha mask [%d] matches.\n", + pFormats[f].type, pFormats[f].depth, pFormats[f].direct.red, pFormats[f].direct.green, + pFormats[f].direct.blue, pFormats[f].direct.redMask, pFormats[f].direct.greenMask, + pFormats[f].direct.blueMask, pFormats[f].direct.alpha, pFormats[f].direct.alphaMask); + #endif + } + else + { + #ifdef DEBUG + fprintf(stderr, "PictureCreateDefaultFormats: Format with type [%d] depth [%d] rgb [%d,%d,%d] " + "mask rgb [%d,%d,%d] alpha [%d] alpha mask [%d] doesn't match.\n", + pFormats[f].type, pFormats[f].depth, pFormats[f].direct.red, pFormats[f].direct.green, + pFormats[f].direct.blue, pFormats[f].direct.redMask, pFormats[f].direct.greenMask, + pFormats[f].direct.blueMask, pFormats[f].direct.alpha, pFormats[f].direct.alphaMask); + #endif + } + } + *nformatp = nformats; + return pFormats; +} + +PicturePtr +AllocatePicture (ScreenPtr pScreen) +{ + PictureScreenPtr ps = GetPictureScreen(pScreen); + PicturePtr pPicture; + char *ptr; + DevUnion *ppriv; + unsigned int *sizes; + unsigned int size; + int i; + + pPicture = (PicturePtr) calloc(1, ps->totalPictureSize); + if (!pPicture) + return 0; + ppriv = (DevUnion *)(pPicture + 1); + pPicture->devPrivates = ppriv; + sizes = ps->PicturePrivateSizes; + ptr = (char *)(ppriv + ps->PicturePrivateLen); + for (i = ps->PicturePrivateLen; --i >= 0; ppriv++, sizes++) + { + if ( (size = *sizes) ) + { + ppriv->ptr = (void *)ptr; + ptr += size; + } + else + ppriv->ptr = (void *)NULL; + } + + nxagentPicturePriv(pPicture) -> picture = 0; + + return pPicture; +} + +PicturePtr +CreatePicture (Picture pid, + DrawablePtr pDrawable, + PictFormatPtr pFormat, + Mask vmask, + XID *vlist, + ClientPtr client, + int *error) +{ + PicturePtr pPicture; + PictureScreenPtr ps = GetPictureScreen(pDrawable->pScreen); + + pPicture = AllocatePicture (pDrawable->pScreen); + if (!pPicture) + { + *error = BadAlloc; + return 0; + } + + pPicture->id = pid; + pPicture->pDrawable = pDrawable; + pPicture->pFormat = pFormat; + pPicture->format = pFormat->format | (pDrawable->bitsPerPixel << 24); + if (pDrawable->type == DRAWABLE_PIXMAP) + { + /* + * Let picture always point to the virtual pixmap. + * For sure this is not the best way to deal with + * the virtual frame-buffer. + */ + pPicture->pDrawable = nxagentVirtualDrawable(pDrawable); + + ++((PixmapPtr)pDrawable)->refcnt; + pPicture->pNext = 0; + } + else + { + pPicture->pNext = GetPictureWindow(((WindowPtr) pDrawable)); + SetPictureWindow(((WindowPtr) pDrawable), pPicture); + } + + SetPictureToDefaults (pPicture); + + if (vmask) + *error = ChangePicture (pPicture, vmask, vlist, 0, client); + else + *error = Success; + if (*error == Success) + *error = (*ps->CreatePicture) (pPicture); + if (*error != Success) + { + FreePicture (pPicture, (XID) 0); + pPicture = 0; + } + return pPicture; +} + +PicturePtr +CreateSolidPicture (Picture pid, xRenderColor *color, int *error) +{ + PicturePtr pPicture; + pPicture = createSourcePicture(); + if (!pPicture) { + *error = BadAlloc; + return 0; + } + + pPicture->id = pid; + pPicture->pSourcePict = (SourcePictPtr) calloc(1, sizeof(PictSolidFill)); + if (!pPicture->pSourcePict) { + *error = BadAlloc; + free(pPicture); + return 0; + } + pPicture->pSourcePict->type = SourcePictTypeSolidFill; + pPicture->pSourcePict->solidFill.color = xRenderColorToCard32(*color); + pPicture->pSourcePict->solidFill.fullColor.alpha=color->alpha; + pPicture->pSourcePict->solidFill.fullColor.red=color->red; + pPicture->pSourcePict->solidFill.fullColor.green=color->green; + pPicture->pSourcePict->solidFill.fullColor.blue=color->blue; + return pPicture; +} + +static PicturePtr createSourcePicture(void) +{ + PicturePtr pPicture; + + extern int nxagentPicturePrivateIndex; + + unsigned int totalPictureSize; + + DevUnion *ppriv; + + char *privPictureRecAddr; + + int i; + + /* + * Compute size of entire PictureRect, plus privates. + */ + + totalPictureSize = sizeof(PictureRec) + + picturePrivateCount * sizeof(DevUnion) + + sizeof(nxagentPrivPictureRec); + + pPicture = (PicturePtr) calloc(1, totalPictureSize); + + if (pPicture != NULL) + { + ppriv = (DevUnion *) (pPicture + 1); + + for (i = 0; i < picturePrivateCount; ++i) + { + /* + * Other privates are inaccessible. + */ + + ppriv[i].ptr = NULL; + } + + privPictureRecAddr = (char *) &ppriv[picturePrivateCount]; + + ppriv[nxagentPicturePrivateIndex].ptr = (void *) privPictureRecAddr; + + pPicture -> devPrivates = ppriv; + + nxagentPicturePriv(pPicture) -> picture = 0; + } + + pPicture->pDrawable = 0; + pPicture->pFormat = 0; + pPicture->pNext = 0; + + SetPictureToDefaults(pPicture); + return pPicture; +} + +int +FreePicture (void * value, + XID pid) +{ + PicturePtr pPicture = (PicturePtr) value; + + if (--pPicture->refcnt == 0) + { + nxagentDestroyPicture(pPicture); + + if (pPicture->transform) + free (pPicture->transform); + if (!pPicture->pDrawable) { + if (pPicture->pSourcePict) { + if (pPicture->pSourcePict->type != SourcePictTypeSolidFill) + free(pPicture->pSourcePict->linear.stops); + free(pPicture->pSourcePict); + } + } else { + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + + if (pPicture->alphaMap) + FreePicture ((void *) pPicture->alphaMap, (XID) 0); + (*ps->DestroyPicture) (pPicture); + (*ps->DestroyPictureClip) (pPicture); + if (pPicture->pDrawable->type == DRAWABLE_WINDOW) + { + WindowPtr pWindow = (WindowPtr) pPicture->pDrawable; + PicturePtr *pPrev; + + for (pPrev = (PicturePtr *) &((pWindow)->devPrivates[PictureWindowPrivateIndex].ptr); + *pPrev; + pPrev = &(*pPrev)->pNext) + { + if (*pPrev == pPicture) + { + *pPrev = pPicture->pNext; + break; + } + } + } + else if (pPicture->pDrawable->type == DRAWABLE_PIXMAP) + { + (*pScreen->DestroyPixmap) ((PixmapPtr)pPicture->pDrawable); + } + } + free (pPicture); + } + return Success; +} + +#ifndef True +# define True 1 +#endif + +#ifndef False +# define False 0 +#endif + +void nxagentReconnectPictFormat(void*, XID, void*); + +Bool nxagentReconnectAllPictFormat(void *p) +{ + PictFormatPtr formats_old, formats; + int nformats, nformats_old; + VisualPtr pVisual; + Bool success = True; + Bool matched; + int i, n; + CARD32 type, a, r, g, b; + + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_PICTFORMAT_DEBUG) + fprintf(stderr, "nxagentReconnectAllPictFormat\n"); + #endif + + formats_old = GetPictureScreen(nxagentDefaultScreen) -> formats; + nformats_old = GetPictureScreen(nxagentDefaultScreen) -> nformats; + + /* + * TODO: We could copy PictureCreateDefaultFormats, + * in order not to waste ID with FakeClientID(). + */ + formats = PictureCreateDefaultFormats (nxagentDefaultScreen, &nformats); + + if (!formats) + return False; + + for (n = 0; n < nformats; n++) + { + if (formats[n].type == PictTypeIndexed) + { + pVisual = nxagentVisualFromID(nxagentDefaultScreen, formats[n].index.vid); + + if ((pVisual->class | DynamicClass) == PseudoColor) + type = PICT_TYPE_COLOR; + else + type = PICT_TYPE_GRAY; + a = r = g = b = 0; + } + else + { + if ((formats[n].direct.redMask| + formats[n].direct.blueMask| + formats[n].direct.greenMask) == 0) + type = PICT_TYPE_A; + else if (formats[n].direct.red > formats[n].direct.blue) + type = PICT_TYPE_ARGB; + else + type = PICT_TYPE_ABGR; + a = Ones (formats[n].direct.alphaMask); + r = Ones (formats[n].direct.redMask); + g = Ones (formats[n].direct.greenMask); + b = Ones (formats[n].direct.blueMask); + } + formats[n].format = PICT_FORMAT(0,type,a,r,g,b); + } + + for (n = 0; n < nformats_old; n++) + { + for (i = 0, matched = False; (!matched) && (i < nformats); i++) + { + if (formats_old[n].format == formats[i].format && + formats_old[n].type == formats[i].type && + formats_old[n].direct.red == formats[i].direct.red && + formats_old[n].direct.green == formats[i].direct.green && + formats_old[n].direct.blue == formats[i].direct.blue && + formats_old[n].direct.redMask == formats[i].direct.redMask && + formats_old[n].direct.greenMask == formats[i].direct.greenMask && + formats_old[n].direct.blueMask == formats[i].direct.blueMask && + formats_old[n].direct.alpha == formats[i].direct.alpha && + formats_old[n].direct.alphaMask == formats[i].direct.alphaMask) + { + /* + * Regard depth 16 and 15 as were the same, if all other values match. + */ + + if ((formats_old[n].depth == formats[i].depth) || + ((formats_old[n].depth == 15 || formats_old[n].depth == 16) && + (formats[i].depth == 15 || formats[i].depth == 16))) + { + matched = True; + } + } + } + + if (!matched) + { + return False; + } + } + + free(formats); + + /* TODO: Perhaps do i have to do PictureFinishInit ?. */ + /* TODO: We have to check for new Render protocol version. */ + + for (i = 0; (i < MAXCLIENTS) && (success); i++) + { + if (clients[i]) + { + FindClientResourcesByType(clients[i], PictFormatType, nxagentReconnectPictFormat, &success); + } + } + + return success; +} + +/* + * It seem we don't have nothing + * to do for reconnect PictureFormat. + */ + +void nxagentReconnectPictFormat(void *p0, XID x1, void *p2) +{ + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_PICTFORMAT_DEBUG) + fprintf(stderr, "nxagentReconnectPictFormat.\n"); + #endif +} + +/* + * The set of picture formats may change considerably + * between different X servers. This poses a problem + * while migrating NX sessions, because a requisite to + * successfully reconnect the session is that all pic- + * ture formats have to be available on the new X server. + * To reduce such problems, we use a limited set of + * pictures available on the most X servers. + */ + +void nxagentPictureCreateDefaultFormats(ScreenPtr pScreen, FormatInitRec *formats, int *nformats) +{ + DepthPtr pDepth; + VisualPtr pVisual; + + CARD32 format; + CARD8 depth; + + int r, g, b; + int bpp; + int d; + int v; + + + formats[*nformats].format = PICT_a1; + formats[*nformats].depth = 1; + *nformats += 1; + formats[*nformats].format = PICT_a4; + formats[*nformats].depth = 4; + *nformats += 1; + formats[*nformats].format = PICT_a8; + formats[*nformats].depth = 8; + *nformats += 1; + formats[*nformats].format = PICT_a8r8g8b8; + formats[*nformats].depth = 32; + *nformats += 1; + + /* + * This format should be required by the + * protocol, but it's not used by Xgl. + * + * formats[*nformats].format = PICT_x8r8g8b8; + * formats[*nformats].depth = 32; + * *nformats += 1; + */ + + /* now look through the depths and visuals adding other formats */ + for (v = 0; v < pScreen->numVisuals; v++) + { + pVisual = &pScreen->visuals[v]; + depth = visualDepth (pScreen, pVisual); + if (!depth) + continue; + + bpp = BitsPerPixel (depth); + + switch (pVisual->class) + { + case DirectColor: + case TrueColor: + r = Ones (pVisual->redMask); + g = Ones (pVisual->greenMask); + b = Ones (pVisual->blueMask); + + if (pVisual->offsetBlue == 0 && + pVisual->offsetGreen == b && + pVisual->offsetRed == b + g) + { + format = PICT_FORMAT(bpp, PICT_TYPE_ARGB, 0, r, g, b); + *nformats = addFormat (formats, *nformats, format, depth); + } + break; + case StaticColor: + case PseudoColor: + case StaticGray: + case GrayScale: + break; + } + } + + for (d = 0; d < pScreen -> numDepths; d++) + { + pDepth = &pScreen -> allowedDepths[d]; + bpp = BitsPerPixel(pDepth -> depth); + + switch (bpp) { + case 16: + if (pDepth->depth == 15) + { + *nformats = addFormat (formats, *nformats, + PICT_x1r5g5b5, pDepth->depth); + } + + if (pDepth->depth == 16) + { + *nformats = addFormat (formats, *nformats, + PICT_r5g6b5, pDepth->depth); + } + break; + case 24: + if (pDepth->depth == 24) + { + *nformats = addFormat (formats, *nformats, + PICT_r8g8b8, pDepth->depth); + } + break; + case 32: + if (pDepth->depth == 24) + { + *nformats = addFormat (formats, *nformats, + PICT_x8r8g8b8, pDepth->depth); + } + break; + } + } +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXpicturestr_PictSolidFill.h b/nx-X11/programs/Xserver/hw/nxagent/NXpicturestr_PictSolidFill.h new file mode 100644 index 000000000..9cd73db5c --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXpicturestr_PictSolidFill.h @@ -0,0 +1,63 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * $Id: picturestr.h,v 1.15 2005/12/09 18:35:21 ajax Exp $ + * + * Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Keith Packard, SuSE, Inc. + */ + +/* this header file gets included into Xserver/render/picturestr.h */ + +#ifndef NX_PICTURESTR_PICTSOLIDFILL_H +#define NX_PICTURESTR_PICTSOLIDFILL_H 1 + + +typedef struct _PictSolidFill { + unsigned int type; + CARD32 color; + xRenderColor fullColor; +} PictSolidFill, *PictSolidFillPtr; + +#endif /* NX_PICTURESTR_PICTSOLIDFILL_H */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXproperty.c b/nx-X11/programs/Xserver/hw/nxagent/NXproperty.c new file mode 100644 index 000000000..ee77eb64e --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXproperty.c @@ -0,0 +1,653 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#include "../../dix/property.c" + +#include "Options.h" +#include "Rootless.h" +#include "Client.h" +#include "Windows.h" + +extern Atom clientCutProperty; + +#ifdef NXAGENT_SERVER +typedef struct +{ + CARD32 state; + Window icon; +} +nxagentWMStateRec; +#endif + +int +ProcChangeProperty(ClientPtr client) +{ + WindowPtr pWin; + char format, mode; + unsigned long len; + int sizeInBytes; + int totalSize; + int err; + REQUEST(xChangePropertyReq); + + REQUEST_AT_LEAST_SIZE(xChangePropertyReq); + UpdateCurrentTime(); + format = stuff->format; + mode = stuff->mode; + if ((mode != PropModeReplace) && (mode != PropModeAppend) && + (mode != PropModePrepend)) + { + client->errorValue = mode; + return BadValue; + } + if ((format != 8) && (format != 16) && (format != 32)) + { + client->errorValue = format; + return BadValue; + } + len = stuff->nUnits; + if (len > ((0xffffffff - sizeof(xChangePropertyReq)) >> 2)) + return BadLength; + sizeInBytes = format>>3; + totalSize = len * sizeInBytes; + REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize); + +#ifdef NXAGENT_CLIPBOARD + { + extern WindowPtr nxagentGetClipboardWindow(Atom, WindowPtr); + + pWin = nxagentGetClipboardWindow(stuff->property, NULL); + } + + if (pWin == NULL) +#endif + pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client, + DixWriteAccess); + if (!pWin) + return(BadWindow); + if (!ValidAtom(stuff->property)) + { + client->errorValue = stuff->property; + return(BadAtom); + } + if (!ValidAtom(stuff->type)) + { + client->errorValue = stuff->type; + return(BadAtom); + } + +#ifdef XCSECURITY + switch (SecurityCheckPropertyAccess(client, pWin, stuff->property, + DixWriteAccess)) + { + case SecurityErrorOperation: + client->errorValue = stuff->property; + return BadAtom; + case SecurityIgnoreOperation: + return Success; + } +#endif + +#ifdef NXAGENT_ARTSD + { + /* Do not process MCOPGLOBALS property changes, + they are already set reflecting the server side settings. + Just return success. + */ + extern Atom mcop_local_atom; + if (stuff->property == mcop_local_atom) + return client->noClientException; + } +#endif + + err = ChangeWindowProperty(pWin, stuff->property, stuff->type, (int)format, + (int)mode, len, (void *)&stuff[1], TRUE); + if (err != Success) + return err; + else + { + if (nxagentOption(Rootless) == 1) + { + nxagentExportProperty(pWin, stuff->property, stuff->type, (int) format, + (int) mode, len, (void *) &stuff[1]); + } + + nxagentGuessClientHint(client, stuff->property, (char *) &stuff[1]); + + nxagentGuessShadowHint(client, stuff->property); + + #ifdef NX_DEBUG_INPUT + nxagentGuessDumpInputInfo(client, stuff->property, (char *) &stuff[1]); + #endif + + return client->noClientException; + } +} + +int +ChangeWindowProperty(WindowPtr pWin, Atom property, Atom type, int format, + int mode, unsigned long len, void * value, + Bool sendevent) +{ + PropertyPtr pProp; + xEvent event; + int sizeInBytes; + int totalSize; + void * data; + int copySize; + + memset(&event, 0, sizeof(xEvent)); + + sizeInBytes = format>>3; + totalSize = len * sizeInBytes; + + copySize = nxagentOption(CopyBufferSize); + + if (copySize != COPY_UNLIMITED && property == clientCutProperty) + { + if (totalSize > copySize) + { + totalSize = copySize; + totalSize = totalSize - (totalSize % sizeInBytes); + len = totalSize / sizeInBytes; + } + } + + /* first see if property already exists */ + + pProp = wUserProps (pWin); + while (pProp) + { + if (pProp->propertyName == property) + break; + pProp = pProp->next; + } + if (!pProp) /* just add to list */ + { + if (!pWin->optional && !MakeWindowOptional (pWin)) + return(BadAlloc); + pProp = (PropertyPtr)malloc(sizeof(PropertyRec)); + if (!pProp) + return(BadAlloc); + data = (void *)malloc(totalSize); + if (!data && len) + { + free(pProp); + return(BadAlloc); + } + pProp->propertyName = property; + pProp->type = type; + pProp->format = format; + pProp->data = data; + if (len) + memmove((char *)data, (char *)value, totalSize); + pProp->size = len; + pProp->next = pWin->optional->userProps; + pWin->optional->userProps = pProp; + } + else + { + /* To append or prepend to a property the request format and type + must match those of the already defined property. The + existing format and type are irrelevant when using the mode + "PropModeReplace" since they will be written over. */ + + if ((format != pProp->format) && (mode != PropModeReplace)) + return(BadMatch); + if ((pProp->type != type) && (mode != PropModeReplace)) + return(BadMatch); + if (mode == PropModeReplace) + { + if (totalSize != pProp->size * (pProp->format >> 3)) + { + data = (void *)realloc(pProp->data, totalSize); + if (!data && len) + return(BadAlloc); + pProp->data = data; + } + if (len) + memmove((char *)pProp->data, (char *)value, totalSize); + pProp->size = len; + pProp->type = type; + pProp->format = format; + } + else if (len == 0) + { + /* do nothing */ + } + else if (mode == PropModeAppend) + { + data = (void *)realloc(pProp->data, + sizeInBytes * (len + pProp->size)); + if (!data) + return(BadAlloc); + pProp->data = data; + memmove(&((char *)data)[pProp->size * sizeInBytes], + (char *)value, + totalSize); + pProp->size += len; + } + else if (mode == PropModePrepend) + { + data = (void *)malloc(sizeInBytes * (len + pProp->size)); + if (!data) + return(BadAlloc); + memmove(&((char *)data)[totalSize], (char *)pProp->data, + (int)(pProp->size * sizeInBytes)); + memmove((char *)data, (char *)value, totalSize); + free(pProp->data); + pProp->data = data; + pProp->size += len; + } + } + if (sendevent) + { + event.u.u.type = PropertyNotify; + event.u.property.window = pWin->drawable.id; + event.u.property.state = PropertyNewValue; + event.u.property.atom = pProp->propertyName; + event.u.property.time = currentTime.milliseconds; + DeliverEvents(pWin, &event, 1, (WindowPtr)NULL); + } + return(Success); +} + +/***************** + * GetProperty + * If type Any is specified, returns the property from the specified + * window regardless of its type. If a type is specified, returns the + * property only if its type equals the specified type. + * If delete is True and a property is returned, the property is also + * deleted from the window and a PropertyNotify event is generated on the + * window. + *****************/ + +int +ProcGetProperty(ClientPtr client) +{ + PropertyPtr pProp, prevProp; + unsigned long n, len, ind; + WindowPtr pWin; + xGetPropertyReply reply; + REQUEST(xGetPropertyReq); + + REQUEST_SIZE_MATCH(xGetPropertyReq); + + if (stuff->delete) + UpdateCurrentTime(); + pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client, + DixReadAccess); + if (!pWin) + return BadWindow; + + if (!ValidAtom(stuff->property)) + { + client->errorValue = stuff->property; + return(BadAtom); + } + if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) + { + client->errorValue = stuff->delete; + return(BadValue); + } + if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) + { + client->errorValue = stuff->type; + return(BadAtom); + } + + pProp = wUserProps (pWin); + prevProp = (PropertyPtr)NULL; + while (pProp) + { + if (pProp->propertyName == stuff->property) + break; + prevProp = pProp; + pProp = pProp->next; + } + + memset(&reply, 0, sizeof(xGetPropertyReply)); + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + #ifdef NXAGENT_SERVER + + /* + * Creating a reply for WM_STATE property if it doesn't exist. + * This is intended to allow drag & drop work in JAva 1.6 when + * the agent is connected to NXWin in multiwindow mode. + */ + + if (nxagentOption(Rootless) && + nxagentWindowTopLevel(pWin) && + (!pProp) && + strcmp(NameForAtom(stuff->property), "WM_STATE") == 0) + { + nxagentWMStateRec wmState; + nxagentWMStateRec *wmsP = &wmState; + + memset(&wmState, 0, sizeof(nxagentWMStateRec)); + wmState.state = 1; + wmState.icon = None; + + if (ChangeWindowProperty(pWin, stuff->property, stuff->property, 32, 0, 2, &wmState, 1) == Success) + { + nxagentExportProperty(pWin, stuff->property, stuff->property, 32, 0, 2, &wmState); + } + + n = 8; + ind = stuff->longOffset << 2; + + if (n < ind) + { + client->errorValue = stuff->longOffset; + return BadValue; + } + + len = min(n - ind, 4 * stuff->longLength); + + reply.bytesAfter = n - (ind + len); + reply.length = (len + 3) >> 2; + + reply.format = 32; + reply.nItems = len / 4; + reply.propertyType = stuff->property; + + WriteReplyToClient(client, sizeof(xGenericReply), &reply); + + if (len) + { + client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; + + WriteSwappedDataToClient(client, len, (char *)wmsP + ind); + } + + return(client->noClientException); + } + #endif + + if (!pProp) + return NullPropertyReply(client, None, 0, &reply); + +#ifdef XCSECURITY + { + Mask access_mode = DixReadAccess; + + if (stuff->delete) + access_mode |= DixDestroyAccess; + switch(SecurityCheckPropertyAccess(client, pWin, stuff->property, + access_mode)) + { + case SecurityErrorOperation: + client->errorValue = stuff->property; + return BadAtom;; + case SecurityIgnoreOperation: + return NullPropertyReply(client, pProp->type, pProp->format, + &reply); + } + } +#endif + /* If the request type and actual type don't match. Return the + property information, but not the data. */ + + if (((stuff->type != pProp->type) && + (stuff->type != AnyPropertyType)) + ) + { + reply.bytesAfter = pProp->size; + reply.format = pProp->format; + reply.length = 0; + reply.nItems = 0; + reply.propertyType = pProp->type; + WriteReplyToClient(client, sizeof(xGenericReply), &reply); + return(Success); + } + +/* + * Return type, format, value to client + */ + n = (pProp->format/8) * pProp->size; /* size (bytes) of prop */ + ind = stuff->longOffset << 2; + + /* If longOffset is invalid such that it causes "len" to + be negative, it's a value error. */ + + if (n < ind) + { + client->errorValue = stuff->longOffset; + return BadValue; + } + + len = min(n - ind, 4 * stuff->longLength); + + reply.bytesAfter = n - (ind + len); + reply.format = pProp->format; + reply.length = (len + 3) >> 2; + reply.nItems = len / (pProp->format / 8 ); + reply.propertyType = pProp->type; + + if (stuff->delete && (reply.bytesAfter == 0)) + { /* send the event */ + xEvent event; + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = PropertyNotify; + event.u.property.window = pWin->drawable.id; + event.u.property.state = PropertyDelete; + event.u.property.atom = pProp->propertyName; + event.u.property.time = currentTime.milliseconds; + DeliverEvents(pWin, &event, 1, (WindowPtr)NULL); + } + + WriteReplyToClient(client, sizeof(xGenericReply), &reply); + if (len) + { + switch (reply.format) { + case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break; + case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break; + default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break; + } + WriteSwappedDataToClient(client, len, + (char *)pProp->data + ind); + } + + if (stuff->delete && (reply.bytesAfter == 0)) + { /* delete the Property */ + if (prevProp == (PropertyPtr)NULL) /* takes care of head */ + { + if (!(pWin->optional->userProps = pProp->next)) + CheckWindowOptionalNeed (pWin); + } + else + prevProp->next = pProp->next; + free(pProp->data); + free(pProp); + } + return(client->noClientException); +} + +#ifdef NXAGENT_CLIPBOARD +/* GetWindowProperty clipboard use only */ +int +GetWindowProperty(pWin, property, longOffset, longLength, delete, + type, actualType, format, nItems, bytesAfter, propData ) + WindowPtr pWin; + Atom property; + long longOffset; + long longLength; + Bool delete; + Atom type; + Atom *actualType; + int *format; + unsigned long *nItems; + unsigned long *bytesAfter; + unsigned char **propData; +{ + PropertyPtr pProp, prevProp; + unsigned long n, len, ind; + + if (!pWin) + return BadWindow; + + + if (!ValidAtom(property)) + { + return(BadAtom); + } + if ((type != AnyPropertyType) && !ValidAtom(type)) + { + return(BadAtom); + } + + pProp = wUserProps (pWin); + prevProp = (PropertyPtr)NULL; + + while (pProp) + { + if (pProp->propertyName == property) + break; + prevProp = pProp; + pProp = pProp->next; + } + + + if (!pProp) + return (BadAtom); + + /* If the request type and actual type don't match. Return the + property information, but not the data. */ + + if (((type != pProp->type) && + (type != AnyPropertyType)) + ) + { + *bytesAfter = pProp->size; + *format = pProp->format; + *nItems = 0; + *actualType = pProp->type; + return(Success); + } + +/* + * Return type, format, value to client + */ + n = (pProp->format/8) * pProp->size; /* size (bytes) of prop */ + ind = longOffset << 2; + + /* If longOffset is invalid such that it causes "len" to + be negative, it's a value error. */ + + if (n < ind) + { + return BadValue; + } + + len = min(n - ind, 4 * longLength); + + *bytesAfter = n - (ind + len); + *format = pProp->format; + *nItems = len / (pProp->format / 8 ); + *actualType = pProp->type; + + if (delete && (*bytesAfter == 0)) + { /* send the event */ + xEvent event; + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = PropertyNotify; + event.u.property.window = pWin->drawable.id; + event.u.property.state = PropertyDelete; + event.u.property.atom = pProp->propertyName; + event.u.property.time = currentTime.milliseconds; + DeliverEvents(pWin, &event, 1, (WindowPtr)NULL); + } + + if (len) + { + *propData = (unsigned char *)(pProp->data) + ind; + } + + if (delete && (*bytesAfter == 0)) + { /* delete the Property */ + if (prevProp == (PropertyPtr)NULL) /* takes care of head */ + { + if (!(pWin->optional->userProps = pProp->next)) + CheckWindowOptionalNeed (pWin); + } + else + prevProp->next = pProp->next; + free(pProp->data); + free(pProp); + } + return(Success); +} +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXrender.c b/nx-X11/programs/Xserver/hw/nxagent/NXrender.c new file mode 100644 index 000000000..691b260cf --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXrender.c @@ -0,0 +1,1730 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + * Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Keith Packard, SuSE, Inc. + */ + +#include "../render/render.c" + +#include "Trap.h" + +#include "Render.h" +#include "Pixmaps.h" +#include "Options.h" +#include "Screen.h" +#include "Cursor.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#ifdef TEST +#include "Literals.h" +#endif + +/* + * From NXglyph.c. + */ + +extern +void GlyphExtents(int nlist, GlyphListPtr list, + GlyphPtr *glyphs, BoxPtr extents); + +/* + * From NXmitrap.c. + */ + +extern +void miTrapezoidBounds (int ntrap, xTrapezoid *traps, BoxPtr box); + +/* + * Functions from Render.c. + */ + +extern int nxagentCursorSaveRenderInfo(ScreenPtr, CursorPtr); +extern void nxagentCursorPostSaveRenderInfo(CursorPtr, ScreenPtr, PicturePtr, int, int); +extern int nxagentRenderRealizeCursor(ScreenPtr, CursorPtr); +extern int nxagentCreatePicture(PicturePtr, Mask); +extern void nxagentChangePicture(PicturePtr, Mask); +extern int nxagentChangePictureClip(PicturePtr, int, int, xRectangle *, int, int); +extern void nxagentComposite(CARD8, PicturePtr, PicturePtr, PicturePtr, INT16, INT16, + INT16, INT16, INT16, INT16, CARD16, CARD16); +extern void nxagentCompositeRects(CARD8, PicturePtr, xRenderColor *, int, xRectangle *); +extern void nxagentCreateGlyphSet(GlyphSetPtr glyphSet); +extern void nxagentReferenceGlyphSet(GlyphSetPtr glyphSet); +extern void nxagentFreeGlyphs(GlyphSetPtr glyphSet, CARD32 *gids, int nglyph); +extern void nxagentFreeGlyphSet(GlyphSetPtr glyphSet); +extern void nxagentSetPictureTransform(PicturePtr pPicture, void * transform); +extern void nxagentSetPictureFilter(PicturePtr pPicture, char *filter, int name_size, + void * params, int nparams); +extern void nxagentTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, int ntrap, xTrapezoid *traps); +extern void nxagentRenderCreateSolidFill(PicturePtr pPicture, xRenderColor *color); +extern void nxagentRenderCreateLinearGradient(PicturePtr pPicture, xPointFixed *p1, + xPointFixed *p2, int nStops, + xFixed *stops, + xRenderColor *colors); +extern void nxagentRenderCreateRadialGradient(PicturePtr pPicture, xPointFixed *inner, + xPointFixed *outer, + xFixed innerRadius, + xFixed outerRadius, + int nStops, + xFixed *stops, + xRenderColor *colors); +extern void nxagentRenderCreateConicalGradient(PicturePtr pPicture, + xPointFixed *center, + xFixed angle, int nStops, + xFixed *stops, + xRenderColor *colors); + +/* + * The void pointer is actually a XGlyphElt8. + */ + +void nxagentGlyphs(CARD8, PicturePtr, PicturePtr, PictFormatPtr, + INT16, INT16, int, void *, int, GlyphPtr *); + +static int +ProcRenderQueryVersion (ClientPtr client) +{ + RenderClientPtr pRenderClient = GetRenderClient (client); + xRenderQueryVersionReply rep; + REQUEST(xRenderQueryVersionReq); + + REQUEST_SIZE_MATCH(xRenderQueryVersionReq); + + pRenderClient->major_version = stuff->majorVersion; + pRenderClient->minor_version = stuff->minorVersion; + + memset(&rep, 0, sizeof(xRenderQueryVersionReply)); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = nxagentRenderVersionMajor; + rep.minorVersion = nxagentRenderVersionMinor; + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.majorVersion); + swapl(&rep.minorVersion); + } + WriteToClient(client, sizeof(xRenderQueryVersionReply), &rep); + return (client->noClientException); +} + +static int +ProcRenderQueryPictFormats (ClientPtr client) +{ + RenderClientPtr pRenderClient = GetRenderClient (client); + xRenderQueryPictFormatsReply *reply; + xPictScreen *pictScreen; + xPictDepth *pictDepth; + xPictVisual *pictVisual; + xPictFormInfo *pictForm; + CARD32 *pictSubpixel; + ScreenPtr pScreen; + VisualPtr pVisual; + DepthPtr pDepth; + int v, d; + PictureScreenPtr ps; + PictFormatPtr pFormat; + int nformat; + int ndepth; + int nvisual; + int rlength; + int s; + int numScreens; + int numSubpixel; + + extern int nxagentAlphaEnabled; +/* REQUEST(xRenderQueryPictFormatsReq); */ + + REQUEST_SIZE_MATCH(xRenderQueryPictFormatsReq); + +#ifdef PANORAMIX + if (noPanoramiXExtension) + numScreens = screenInfo.numScreens; + else + numScreens = ((xConnSetup *)ConnectionInfo)->numRoots; +#else + numScreens = screenInfo.numScreens; +#endif + ndepth = nformat = nvisual = 0; + for (s = 0; s < numScreens; s++) + { + pScreen = screenInfo.screens[s]; + for (d = 0; d < pScreen->numDepths; d++) + { + pDepth = pScreen->allowedDepths + d; + ++ndepth; + + for (v = 0; v < pDepth->numVids; v++) + { + pVisual = findVisual (pScreen, pDepth->vids[v]); + if (pVisual && PictureMatchVisual (pScreen, pDepth->depth, pVisual)) + ++nvisual; + } + } + ps = GetPictureScreenIfSet(pScreen); + if (ps) + nformat += ps->nformats; + } + if (pRenderClient->major_version == 0 && pRenderClient->minor_version < 6) + numSubpixel = 0; + else + numSubpixel = numScreens; + + rlength = (sizeof (xRenderQueryPictFormatsReply) + + nformat * sizeof (xPictFormInfo) + + numScreens * sizeof (xPictScreen) + + ndepth * sizeof (xPictDepth) + + nvisual * sizeof (xPictVisual) + + numSubpixel * sizeof (CARD32)); + reply = (xRenderQueryPictFormatsReply *) calloc (1, rlength); + if (!reply) + return BadAlloc; + reply->type = X_Reply; + reply->sequenceNumber = client->sequence; + reply->length = (rlength - sizeof(xGenericReply)) >> 2; + reply->numFormats = nformat; + reply->numScreens = numScreens; + reply->numDepths = ndepth; + reply->numVisuals = nvisual; + reply->numSubpixel = numSubpixel; + + pictForm = (xPictFormInfo *) (reply + 1); + + for (s = 0; s < numScreens; s++) + { + pScreen = screenInfo.screens[s]; + ps = GetPictureScreenIfSet(pScreen); + if (ps) + { + for (nformat = 0, pFormat = ps->formats; + nformat < ps->nformats; + nformat++, pFormat++) + { + pictForm->id = pFormat->id; + pictForm->type = pFormat->type; + pictForm->depth = pFormat->depth; + pictForm->direct.red = pFormat->direct.red; + pictForm->direct.redMask = pFormat->direct.redMask; + pictForm->direct.green = pFormat->direct.green; + pictForm->direct.greenMask = pFormat->direct.greenMask; + pictForm->direct.blue = pFormat->direct.blue; + pictForm->direct.blueMask = pFormat->direct.blueMask; + pictForm->direct.alpha = nxagentAlphaEnabled ? pFormat->direct.alpha : 0; + pictForm->direct.alphaMask = pFormat->direct.alphaMask; + if (pFormat->type == PictTypeIndexed && pFormat->index.pColormap) + pictForm->colormap = pFormat->index.pColormap->mid; + else + pictForm->colormap = None; + if (client->swapped) + { + swapl (&pictForm->id); + swaps (&pictForm->direct.red); + swaps (&pictForm->direct.redMask); + swaps (&pictForm->direct.green); + swaps (&pictForm->direct.greenMask); + swaps (&pictForm->direct.blue); + swaps (&pictForm->direct.blueMask); + swaps (&pictForm->direct.alpha); + swaps (&pictForm->direct.alphaMask); + swapl (&pictForm->colormap); + } + pictForm++; + } + } + } + + pictScreen = (xPictScreen *) pictForm; + for (s = 0; s < numScreens; s++) + { + pScreen = screenInfo.screens[s]; + pictDepth = (xPictDepth *) (pictScreen + 1); + ndepth = 0; + for (d = 0; d < pScreen->numDepths; d++) + { + pictVisual = (xPictVisual *) (pictDepth + 1); + pDepth = pScreen->allowedDepths + d; + + nvisual = 0; + for (v = 0; v < pDepth->numVids; v++) + { + pVisual = findVisual (pScreen, pDepth->vids[v]); + if (pVisual && (pFormat = PictureMatchVisual (pScreen, + pDepth->depth, + pVisual))) + { + pictVisual->visual = pVisual->vid; + pictVisual->format = pFormat->id; + if (client->swapped) + { + swapl (&pictVisual->visual); + swapl (&pictVisual->format); + } + pictVisual++; + nvisual++; + } + } + pictDepth->depth = pDepth->depth; + pictDepth->nPictVisuals = nvisual; + if (client->swapped) + { + swaps (&pictDepth->nPictVisuals); + } + ndepth++; + pictDepth = (xPictDepth *) pictVisual; + } + pictScreen->nDepth = ndepth; + ps = GetPictureScreenIfSet(pScreen); + if (ps) + pictScreen->fallback = ps->fallback->id; + else + pictScreen->fallback = 0; + if (client->swapped) + { + swapl (&pictScreen->nDepth); + swapl (&pictScreen->fallback); + } + pictScreen = (xPictScreen *) pictDepth; + } + pictSubpixel = (CARD32 *) pictScreen; + + for (s = 0; s < numSubpixel; s++) + { + pScreen = screenInfo.screens[s]; + ps = GetPictureScreenIfSet(pScreen); + if (ps) + *pictSubpixel = ps->subpixel; + else + *pictSubpixel = SubPixelUnknown; + if (client->swapped) + { + swapl (pictSubpixel); + } + ++pictSubpixel; + } + + if (client->swapped) + { + swaps (&reply->sequenceNumber); + swapl (&reply->length); + swapl (&reply->numFormats); + swapl (&reply->numScreens); + swapl (&reply->numDepths); + swapl (&reply->numVisuals); + swapl (&reply->numSubpixel); + } + WriteToClient(client, rlength, reply); + free (reply); + return client->noClientException; +} + +static int +ProcRenderCreatePicture (ClientPtr client) +{ + PicturePtr pPicture; + DrawablePtr pDrawable; + PictFormatPtr pFormat; + int len; + int error; + REQUEST(xRenderCreatePictureReq); + + REQUEST_AT_LEAST_SIZE(xRenderCreatePictureReq); + + LEGAL_NEW_RESOURCE(stuff->pid, client); + SECURITY_VERIFY_DRAWABLE(pDrawable, stuff->drawable, client, + DixWriteAccess); + pFormat = (PictFormatPtr) SecurityLookupIDByType (client, + stuff->format, + PictFormatType, + DixReadAccess); + if (!pFormat) + { + client->errorValue = stuff->format; + return RenderErrBase + BadPictFormat; + } + if (pFormat->depth != pDrawable->depth) + return BadMatch; + len = client->req_len - (sizeof(xRenderCreatePictureReq) >> 2); + if (Ones(stuff->mask) != len) + return BadLength; + + pPicture = CreatePicture (stuff->pid, + pDrawable, + pFormat, + stuff->mask, + (XID *) (stuff + 1), + client, + &error); + if (!pPicture) + return error; + nxagentCreatePicture(pPicture, stuff -> mask); + + if (!AddResource (stuff->pid, PictureType, (void *)pPicture)) + return BadAlloc; + return Success; +} + +static int +ProcRenderChangePicture (ClientPtr client) +{ + PicturePtr pPicture; + REQUEST(xRenderChangePictureReq); + int len; + int error; + + REQUEST_AT_LEAST_SIZE(xRenderChangePictureReq); + VERIFY_PICTURE (pPicture, stuff->picture, client, DixWriteAccess, + RenderErrBase + BadPicture); + + len = client->req_len - (sizeof(xRenderChangePictureReq) >> 2); + if (Ones(stuff->mask) != len) + return BadLength; + + error = ChangePicture (pPicture, stuff->mask, (XID *) (stuff + 1), + (DevUnion *) 0, client); + + nxagentChangePicture(pPicture, stuff->mask); + + return error; +} + +static int +ProcRenderSetPictureClipRectangles (ClientPtr client) +{ + REQUEST(xRenderSetPictureClipRectanglesReq); + PicturePtr pPicture; + int nr; + int result; + + REQUEST_AT_LEAST_SIZE(xRenderSetPictureClipRectanglesReq); + VERIFY_PICTURE (pPicture, stuff->picture, client, DixWriteAccess, + RenderErrBase + BadPicture); + if (!pPicture->pDrawable) + return BadDrawable; + + /* + * The original code used sizeof(xRenderChangePictureReq). + * This was harmless, as both structures have the same size. + * + * nr = (client->req_len << 2) - sizeof(xRenderChangePictureReq); + */ + nr = (client->req_len << 2) - sizeof(xRenderSetPictureClipRectanglesReq); + if (nr & 4) + return BadLength; + nr >>= 3; + result = SetPictureClipRects (pPicture, + stuff->xOrigin, stuff->yOrigin, + nr, (xRectangle *) &stuff[1]); + nxagentChangePictureClip (pPicture, + CT_NONE, + nr, + (xRectangle *) &stuff[1], + (int)stuff -> xOrigin, + (int)stuff -> yOrigin); + + if (client->noClientException != Success) + return(client->noClientException); + else + return(result); +} + +/* + * Check if both pictures have drawables which are + * virtual pixmaps. See the corresponding define + * in NXpicture.c + */ + +#define NXAGENT_PICTURE_ALWAYS_POINTS_TO_VIRTUAL + +#ifdef NXAGENT_PICTURE_ALWAYS_POINTS_TO_VIRTUAL + +#define nxagentCompositePredicate(pSrc, pDst) TRUE + +#else + +/* + * This is still under development. The final + * goal is to let pictures point to the real + * pixmaps instead of pointing to virtuals. + */ + +int nxagentCompositePredicate(PicturePtr pSrc, PicturePtr pDst) +{ + PixmapPtr pPixmap1; + PixmapPtr pPixmap2; + + pPixmap1 = (pSrc -> pDrawable -> type == DRAWABLE_PIXMAP ? + ((PixmapPtr) pSrc -> pDrawable) : NULL); + + pPixmap2 = (pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? + ((PixmapPtr) pDst -> pDrawable) : NULL); + + if (pPixmap1 == NULL || pPixmap2 == NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentCompositePredicate: Case 0.\n"); + #endif + + return FALSE; + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentCompositePredicate: Case 1.\n"); + #endif + + if (nxagentPixmapIsVirtual(pPixmap1) == 1 && + nxagentPixmapIsVirtual(pPixmap2) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentCompositePredicate: Case 2.\n"); + #endif + + return TRUE; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentCompositePredicate: Case 3.\n"); + #endif + + return FALSE; +} + +#endif + +static int +ProcRenderComposite (ClientPtr client) +{ + PicturePtr pSrc, pMask, pDst; + REQUEST(xRenderCompositeReq); + + REQUEST_SIZE_MATCH(xRenderCompositeReq); + if (!PictOpValid (stuff->op)) + { + client->errorValue = stuff->op; + return BadValue; + } + VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess, + RenderErrBase + BadPicture); + if (!pDst->pDrawable) + return BadDrawable; + VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess, + RenderErrBase + BadPicture); + VERIFY_ALPHA (pMask, stuff->mask, client, DixReadAccess, + RenderErrBase + BadPicture); + + if ((pSrc->pDrawable && pSrc->pDrawable->pScreen != pDst->pDrawable->pScreen) || + (pMask && pMask->pDrawable && pDst->pDrawable->pScreen != pMask->pDrawable->pScreen)) + return BadMatch; + + ValidatePicture (pSrc); + if (pMask) + ValidatePicture (pMask); + ValidatePicture (pDst); + + #ifdef NXAGENT_PICTURE_ALWAYS_POINTS_TO_VIRTUAL + + if (nxagentCompositePredicate(pSrc, pDst)) + { + #ifdef TEST + fprintf(stderr, "ProcRenderComposite: Going to composite with " + "source at [%p] mask at [%p] and destination at [%p].\n", + (void *) pSrc, (void *) pMask, (void *) pDst); + #endif + + CompositePicture (stuff->op, + pSrc, + pMask, + pDst, + stuff->xSrc, + stuff->ySrc, + stuff->xMask, + stuff->yMask, + stuff->xDst, + stuff->yDst, + stuff->width, + stuff->height); + } + + #else + + if (pSrc -> pDrawable -> type == DRAWABLE_PIXMAP && + pDst -> pDrawable -> type == DRAWABLE_PIXMAP && + (!pMask || pMask -> pDrawable -> type == DRAWABLE_PIXMAP)) + { + PixmapPtr pVirtualPixmapSrc; + PixmapPtr pVirtualPixmapDst; + PixmapPtr pVirtualPixmapMask; + + PicturePtr pVirtualPictureSrc; + PicturePtr pVirtualPictureDst; + PicturePtr pVirtualPictureMask; + + pVirtualPixmapSrc = (PixmapPtr) pSrc -> pDrawable; + pVirtualPictureSrc = nxagentPixmapPriv(pVirtualPixmapSrc) -> pPicture; + + pVirtualPixmapDst = (PixmapPtr) pDst -> pDrawable; + pVirtualPictureDst = nxagentPixmapPriv(pVirtualPixmapDst) -> pPicture; + + if (pMask) + { + pVirtualPixmapMask = (PixmapPtr) pMask -> pDrawable; + pVirtualPictureMask = nxagentPixmapPriv(pVirtualPixmapMask) -> pPicture; + } + else + { + pVirtualPixmapMask = NULL; + pVirtualPictureMask = NULL; + } + + if (pVirtualPictureSrc && pVirtualPictureDst) + { + #ifdef TEST + fprintf(stderr, "ProcRenderComposite: Going to composite with " + "source at [%p] mask at [%p] and destination at [%p].\n", + (void *) pVirtualPixmapSrc, (void *) pVirtualPixmapMask, + (void *) pVirtualPixmapDst); + #endif + + CompositePicture (stuff->op, + pVirtualPictureSrc, + pVirtualPictureMask, + pVirtualPictureDst, + stuff->xSrc, + stuff->ySrc, + stuff->xMask, + stuff->yMask, + stuff->xDst, + stuff->yDst, + stuff->width, + stuff->height); + } + } + + #endif + + nxagentComposite (stuff -> op, + pSrc, + pMask, + pDst, + stuff -> xSrc, + stuff -> ySrc, + stuff -> xMask, + stuff -> yMask, + stuff -> xDst, + stuff -> yDst, + stuff -> width, + stuff -> height); + + return Success; +} + +static int +ProcRenderTrapezoids (ClientPtr client) +{ + int ntraps; + PicturePtr pSrc, pDst; + PictFormatPtr pFormat; + REQUEST(xRenderTrapezoidsReq); + + REQUEST_AT_LEAST_SIZE(xRenderTrapezoidsReq); + if (!PictOpValid (stuff->op)) + { + client->errorValue = stuff->op; + return BadValue; + } + VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess, + RenderErrBase + BadPicture); + VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess, + RenderErrBase + BadPicture); + if (!pDst->pDrawable) + return BadDrawable; + if (pSrc->pDrawable && pSrc->pDrawable->pScreen != pDst->pDrawable->pScreen) + return BadMatch; + if (stuff->maskFormat) + { + pFormat = (PictFormatPtr) SecurityLookupIDByType (client, + stuff->maskFormat, + PictFormatType, + DixReadAccess); + if (!pFormat) + { + client->errorValue = stuff->maskFormat; + return RenderErrBase + BadPictFormat; + } + } + else + pFormat = 0; + ntraps = (client->req_len << 2) - sizeof (xRenderTrapezoidsReq); + if (ntraps % sizeof (xTrapezoid)) + return BadLength; + ntraps /= sizeof (xTrapezoid); + if (ntraps) + { + if (pFormat != NULL) + { + nxagentTrapezoidExtents = (BoxPtr) malloc(sizeof(BoxRec)); + + miTrapezoidBounds (ntraps, (xTrapezoid *) &stuff[1], nxagentTrapezoidExtents); + } + + if (nxagentCompositePredicate(pSrc, pDst) == 1) + { + CompositeTrapezoids (stuff->op, pSrc, pDst, pFormat, + stuff->xSrc, stuff->ySrc, + ntraps, (xTrapezoid *) &stuff[1]); + } + + nxagentTrapezoids (stuff->op, pSrc, pDst, pFormat, + stuff->xSrc, stuff->ySrc, + ntraps, (xTrapezoid *) &stuff[1]); + + if (nxagentTrapezoidExtents != NullBox) + { + free(nxagentTrapezoidExtents); + + nxagentTrapezoidExtents = NullBox; + } + } + + return client->noClientException; +} + +static int +ProcRenderCreateGlyphSet (ClientPtr client) +{ + GlyphSetPtr glyphSet; + PictFormatPtr format; + int f; + REQUEST(xRenderCreateGlyphSetReq); + + REQUEST_SIZE_MATCH(xRenderCreateGlyphSetReq); + + LEGAL_NEW_RESOURCE(stuff->gsid, client); + format = (PictFormatPtr) SecurityLookupIDByType (client, + stuff->format, + PictFormatType, + DixReadAccess); + if (!format) + { + client->errorValue = stuff->format; + return RenderErrBase + BadPictFormat; + } + switch (format->depth) { + case 1: + f = GlyphFormat1; + break; + case 4: + f = GlyphFormat4; + break; + case 8: + f = GlyphFormat8; + break; + case 16: + f = GlyphFormat16; + break; + case 32: + f = GlyphFormat32; + break; + default: + return BadMatch; + } + if (format->type != PictTypeDirect) + return BadMatch; + glyphSet = AllocateGlyphSet (f, format); + if (!glyphSet) + return BadAlloc; + if (!AddResource (stuff->gsid, GlyphSetType, (void *)glyphSet)) + return BadAlloc; + + nxagentCreateGlyphSet(glyphSet); + + return Success; +} + +static int +ProcRenderReferenceGlyphSet (ClientPtr client) +{ + GlyphSetPtr glyphSet; + REQUEST(xRenderReferenceGlyphSetReq); + + REQUEST_SIZE_MATCH(xRenderReferenceGlyphSetReq); + + LEGAL_NEW_RESOURCE(stuff->gsid, client); + + glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client, + stuff->existing, + GlyphSetType, + DixWriteAccess); + if (!glyphSet) + { + client->errorValue = stuff->existing; + return RenderErrBase + BadGlyphSet; + } + glyphSet->refcnt++; + + nxagentReferenceGlyphSet(glyphSet); + + if (!AddResource (stuff->gsid, GlyphSetType, (void *)glyphSet)) + return BadAlloc; + return client->noClientException; +} + +static int +ProcRenderFreeGlyphSet (ClientPtr client) +{ + GlyphSetPtr glyphSet; + REQUEST(xRenderFreeGlyphSetReq); + + REQUEST_SIZE_MATCH(xRenderFreeGlyphSetReq); + glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client, + stuff->glyphset, + GlyphSetType, + DixDestroyAccess); + if (!glyphSet) + { + client->errorValue = stuff->glyphset; + return RenderErrBase + BadGlyphSet; + } + + nxagentFreeGlyphSet(glyphSet); + + FreeResource (stuff->glyphset, RT_NONE); + return client->noClientException; +} + +static int +ProcRenderFreeGlyphs (ClientPtr client) +{ + REQUEST(xRenderFreeGlyphsReq); + GlyphSetPtr glyphSet; + int nglyph; + CARD32 *gids; + CARD32 glyph; + + REQUEST_AT_LEAST_SIZE(xRenderFreeGlyphsReq); + glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client, + stuff->glyphset, + GlyphSetType, + DixWriteAccess); + if (!glyphSet) + { + client->errorValue = stuff->glyphset; + return RenderErrBase + BadGlyphSet; + } + nglyph = ((client->req_len << 2) - sizeof (xRenderFreeGlyphsReq)) >> 2; + gids = (CARD32 *) (stuff + 1); + + nxagentFreeGlyphs(glyphSet, gids, nglyph); + + while (nglyph-- > 0) + { + glyph = *gids++; + if (!DeleteGlyph (glyphSet, glyph)) + { + client->errorValue = glyph; + return RenderErrBase + BadGlyph; + } + } + return client->noClientException; +} + +typedef struct XGlyphElt8{ + GlyphSet glyphset; + _Xconst char *chars; + int nchars; + int xOff; + int yOff; +} XGlyphElt8; + +static int +ProcRenderCompositeGlyphs (ClientPtr client) +{ + GlyphSetPtr glyphSet; + GlyphSet gs; + PicturePtr pSrc, pDst; + PictFormatPtr pFormat; + GlyphListRec listsLocal[NLOCALDELTA]; + GlyphListPtr lists, listsBase; + GlyphPtr glyphsLocal[NLOCALGLYPH]; + Glyph glyph; + GlyphPtr *glyphs, *glyphsBase; + xGlyphElt *elt; + CARD8 *buffer, *end; + int nglyph; + int nlist; + int space; + int size; + int n; + + XGlyphElt8 *elements, *elementsBase; + + REQUEST(xRenderCompositeGlyphsReq); + + REQUEST_AT_LEAST_SIZE(xRenderCompositeGlyphsReq); + + switch (stuff->renderReqType) { + default: size = 1; break; + case X_RenderCompositeGlyphs16: size = 2; break; + case X_RenderCompositeGlyphs32: size = 4; break; + } + + if (!PictOpValid (stuff->op)) + { + client->errorValue = stuff->op; + return BadValue; + } + VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess, + RenderErrBase + BadPicture); + VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess, + RenderErrBase + BadPicture); + if (!pDst->pDrawable) + return BadDrawable; + if (pSrc->pDrawable && pSrc->pDrawable->pScreen != pDst->pDrawable->pScreen) + return BadMatch; + if (stuff->maskFormat) + { + pFormat = (PictFormatPtr) SecurityLookupIDByType (client, + stuff->maskFormat, + PictFormatType, + DixReadAccess); + if (!pFormat) + { + client->errorValue = stuff->maskFormat; + return RenderErrBase + BadPictFormat; + } + } + else + pFormat = 0; + + glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client, + stuff->glyphset, + GlyphSetType, + DixReadAccess); + if (!glyphSet) + { + client->errorValue = stuff->glyphset; + return RenderErrBase + BadGlyphSet; + } + + buffer = (CARD8 *) (stuff + 1); + end = (CARD8 *) stuff + (client->req_len << 2); + nglyph = 0; + nlist = 0; + while (buffer + sizeof (xGlyphElt) < end) + { + elt = (xGlyphElt *) buffer; + buffer += sizeof (xGlyphElt); + + if (elt->len == 0xff) + { + buffer += 4; + } + else + { + nlist++; + nglyph += elt->len; + space = size * elt->len; + if (space & 3) + space += 4 - (space & 3); + buffer += space; + } + } + if (nglyph <= NLOCALGLYPH) + glyphsBase = glyphsLocal; + else + { + glyphsBase = (GlyphPtr *) malloc (nglyph * sizeof (GlyphPtr)); + if (!glyphsBase) + return BadAlloc; + } + if (nlist <= NLOCALDELTA) + listsBase = listsLocal; + else + { + listsBase = (GlyphListPtr) malloc (nlist * sizeof (GlyphListRec)); + if (!listsBase) + return BadAlloc; + } + + elementsBase = malloc(nlist * sizeof(XGlyphElt8)); + if (!elementsBase) + return BadAlloc; + + buffer = (CARD8 *) (stuff + 1); + glyphs = glyphsBase; + lists = listsBase; + elements = elementsBase; + while (buffer + sizeof (xGlyphElt) < end) + { + elt = (xGlyphElt *) buffer; + buffer += sizeof (xGlyphElt); + + if (elt->len == 0xff) + { + #ifdef DEBUG + fprintf(stderr, "ProcRenderCompositeGlyphs: Glyphset change with base size [%d].\n", + size); + #endif + + if (buffer + sizeof (GlyphSet) < end) + { + memcpy(&gs, buffer, sizeof(GlyphSet)); + glyphSet = (GlyphSetPtr) SecurityLookupIDByType (client, + gs, + GlyphSetType, + DixReadAccess); + if (!glyphSet) + { + client->errorValue = gs; + if (glyphsBase != glyphsLocal) + free (glyphsBase); + if (listsBase != listsLocal) + free (listsBase); + return RenderErrBase + BadGlyphSet; + } + } + buffer += 4; + } + else + { + lists->xOff = elt->deltax; + lists->yOff = elt->deltay; + lists->format = glyphSet->format; + lists->len = 0; + + if (glyphSet -> remoteID == 0) + { + #ifdef TEST + fprintf(stderr, "ProcRenderCompositeGlyphs: Going to reconnect glyphset at [%p].\n", + (void *) glyphSet); + #endif + + nxagentReconnectGlyphSet(glyphSet, (XID) 0, (void*) NULL); + } + + elements -> glyphset = glyphSet -> remoteID; + elements -> chars = (char *) buffer; + elements -> nchars = elt->len; + elements -> xOff = elt->deltax; + elements -> yOff = elt->deltay; + n = elt->len; + while (n--) + { + if (buffer + size <= end) + { + switch (size) { + case 1: + glyph = *((CARD8 *)buffer); break; + case 2: + glyph = *((CARD16 *)buffer); break; + case 4: + default: + glyph = *((CARD32 *)buffer); break; + } + if ((*glyphs = FindGlyph (glyphSet, glyph))) + { + lists->len++; + glyphs++; + } + } + buffer += size; + } + space = size * elt->len; + if (space & 3) + buffer += 4 - (space & 3); + lists++; + elements++; + } + } + if (buffer > end) + return BadLength; + + /* + * We need to know the glyphs extents to synchronize + * the drawables involved in the composite text ope- + * ration. Also we need to synchronize only the back- + * ground of the text we are going to render, so the + * operations on the framebuffer must be executed + * after the X requests. + */ + + nxagentGlyphsExtents = (BoxPtr) malloc(sizeof(BoxRec)); + + GlyphExtents(nlist, listsBase, glyphsBase, nxagentGlyphsExtents); + + nxagentGlyphs(stuff -> op, + pSrc, + pDst, + pFormat, + stuff -> xSrc, + stuff -> ySrc, + nlist, + elementsBase, + size, + glyphsBase); + + if (nxagentCompositePredicate(pSrc, pDst) == 1) + { + #ifdef TEST + fprintf(stderr, "ProcRenderCompositeGlyphs: Going to composite glyphs with " + "source at [%p] and destination at [%p].\n", + (void *) pSrc, (void *) pDst); + #endif + + CompositeGlyphs(stuff -> op, + pSrc, + pDst, + pFormat, + stuff -> xSrc, + stuff -> ySrc, + nlist, + listsBase, + glyphsBase); + } + + free(nxagentGlyphsExtents); + nxagentGlyphsExtents = NullBox; + + if (glyphsBase != glyphsLocal) + free (glyphsBase); + if (listsBase != listsLocal) + free (listsBase); + + free(elementsBase); + + return client->noClientException; +} + +static int +ProcRenderFillRectangles (ClientPtr client) +{ + PicturePtr pDst; + int things; + REQUEST(xRenderFillRectanglesReq); + + REQUEST_AT_LEAST_SIZE (xRenderFillRectanglesReq); + if (!PictOpValid (stuff->op)) + { + client->errorValue = stuff->op; + return BadValue; + } + VERIFY_PICTURE (pDst, stuff->dst, client, DixWriteAccess, + RenderErrBase + BadPicture); + if (!pDst->pDrawable) + return BadDrawable; + + things = (client->req_len << 2) - sizeof(xRenderFillRectanglesReq); + if (things & 4) + return(BadLength); + things >>= 3; + + CompositeRects (stuff->op, + pDst, + &stuff->color, + things, + (xRectangle *) &stuff[1]); + + ValidatePicture (pDst); + nxagentCompositeRects(stuff -> op, + pDst, + &stuff -> color, + things, + (xRectangle *) &stuff[1]); + + return client->noClientException; +} + +static int +ProcRenderCreateCursor (ClientPtr client) +{ + REQUEST(xRenderCreateCursorReq); + PicturePtr pSrc; + ScreenPtr pScreen; + unsigned short width, height; + CARD32 *argbbits, *argb; + unsigned char *srcbits, *srcline; + unsigned char *mskbits, *mskline; + int stride; + int x, y; + int nbytes_mono; + CursorMetricRec cm; + CursorPtr pCursor; + CARD32 twocolor[3]; + int ncolor; + + RealizeCursorProcPtr saveRealizeCursor; + + REQUEST_SIZE_MATCH (xRenderCreateCursorReq); + LEGAL_NEW_RESOURCE(stuff->cid, client); + + VERIFY_PICTURE (pSrc, stuff->src, client, DixReadAccess, + RenderErrBase + BadPicture); + if (!pSrc->pDrawable) + return BadDrawable; + pScreen = pSrc->pDrawable->pScreen; + width = pSrc->pDrawable->width; + height = pSrc->pDrawable->height; + if (height && width > UINT32_MAX/(height*sizeof(CARD32))) + return BadAlloc; + if ( stuff->x > width + || stuff->y > height ) + return (BadMatch); + argbbits = malloc (width * height * sizeof (CARD32)); + if (!argbbits) + return (BadAlloc); + + stride = BitmapBytePad(width); + nbytes_mono = stride*height; + srcbits = (unsigned char *)malloc(nbytes_mono); + if (!srcbits) + { + free (argbbits); + return (BadAlloc); + } + mskbits = (unsigned char *)malloc(nbytes_mono); + if (!mskbits) + { + free(argbbits); + free(srcbits); + return (BadAlloc); + } + bzero ((char *) mskbits, nbytes_mono); + bzero ((char *) srcbits, nbytes_mono); + + if (pSrc->format == PICT_a8r8g8b8) + { + (*pScreen->GetImage) (pSrc->pDrawable, + 0, 0, width, height, ZPixmap, + 0xffffffff, (void *) argbbits); + } + else + { + PixmapPtr pPixmap; + PicturePtr pPicture; + PictFormatPtr pFormat; + int error; + + pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8); + if (!pFormat) + { + free (argbbits); + free (srcbits); + free (mskbits); + return (BadImplementation); + } + pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 32, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pPixmap) + { + free (argbbits); + free (srcbits); + free (mskbits); + return (BadAlloc); + } + pPicture = CreatePicture (0, &pPixmap->drawable, pFormat, 0, 0, + client, &error); + if (!pPicture) + { + free (argbbits); + free (srcbits); + free (mskbits); + return error; + } + (*pScreen->DestroyPixmap) (pPixmap); + CompositePicture (PictOpSrc, + pSrc, 0, pPicture, + 0, 0, 0, 0, 0, 0, width, height); + (*pScreen->GetImage) (pPicture->pDrawable, + 0, 0, width, height, ZPixmap, + 0xffffffff, (void *) argbbits); + FreePicture (pPicture, 0); + } + /* + * Check whether the cursor can be directly supported by + * the core cursor code + */ + ncolor = 0; + argb = argbbits; + for (y = 0; ncolor <= 2 && y < height; y++) + { + for (x = 0; ncolor <= 2 && x < width; x++) + { + CARD32 p = *argb++; + CARD32 a = (p >> 24); + + if (a == 0) /* transparent */ + continue; + if (a == 0xff) /* opaque */ + { + int n; + for (n = 0; n < ncolor; n++) + if (p == twocolor[n]) + break; + if (n == ncolor) + twocolor[ncolor++] = p; + } + else + ncolor = 3; + } + } + + /* + * Convert argb image to two plane cursor + */ + srcline = srcbits; + mskline = mskbits; + argb = argbbits; + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + CARD32 p = *argb++; + + if (ncolor <= 2) + { + CARD32 a = ((p >> 24)); + + SetBit (mskline, x, a != 0); + SetBit (srcline, x, a != 0 && p == twocolor[0]); + } + else + { + CARD32 a = ((p >> 24) * DITHER_SIZE + 127) / 255; + CARD32 i = ((CvtR8G8B8toY15(p) >> 7) * DITHER_SIZE + 127) / 255; + CARD32 d = orderedDither[y&(DITHER_DIM-1)][x&(DITHER_DIM-1)]; + /* Set mask from dithered alpha value */ + SetBit(mskline, x, a > d); + /* Set src from dithered intensity value */ + SetBit(srcline, x, a > d && i <= d); + } + } + srcline += stride; + mskline += stride; + } + /* + * Dither to white and black if the cursor has more than two colors + */ + if (ncolor > 2) + { + twocolor[0] = 0xff000000; + twocolor[1] = 0xffffffff; + } + else + { + free (argbbits); + argbbits = 0; + } + +#define GetByte(p,s) (((p) >> (s)) & 0xff) +#define GetColor(p,s) (GetByte(p,s) | (GetByte(p,s) << 8)) + + cm.width = width; + cm.height = height; + cm.xhot = stuff->x; + cm.yhot = stuff->y; + + /* + * This cursor uses RENDER, so we make sure + * that it is allocated in a way that allows + * the mi and dix layers to handle it but we + * later create it on the server by mirror- + * ing the RENDER operation we got from the + * client. + */ + + saveRealizeCursor = pScreen -> RealizeCursor; + + pScreen -> RealizeCursor = nxagentCursorSaveRenderInfo; + + pCursor = AllocCursorARGB (srcbits, mskbits, argbbits, &cm, + GetColor(twocolor[0], 16), + GetColor(twocolor[0], 8), + GetColor(twocolor[0], 0), + GetColor(twocolor[1], 16), + GetColor(twocolor[1], 8), + GetColor(twocolor[1], 0)); + + pScreen -> RealizeCursor = saveRealizeCursor; + + /* + * Store into the private data members the + * information needed to recreate it at + * reconnection. This is done in two steps + * as in the first step we don't have the + * picture info. + */ + + if (pCursor == NULL) + { + return BadAlloc; + } + + nxagentCursorPostSaveRenderInfo(pCursor, pScreen, pSrc, stuff -> x, stuff -> y); + + nxagentRenderRealizeCursor(pScreen, pCursor); + + if (AddResource(stuff->cid, RT_CURSOR, (void *)pCursor)) + return (client->noClientException); + return BadAlloc; +} + +static int +ProcRenderSetPictureTransform (ClientPtr client) +{ + REQUEST(xRenderSetPictureTransformReq); + PicturePtr pPicture; + int result; + + REQUEST_SIZE_MATCH(xRenderSetPictureTransformReq); + VERIFY_PICTURE (pPicture, stuff->picture, client, DixWriteAccess, + RenderErrBase + BadPicture); + result = SetPictureTransform (pPicture, (PictTransform *) &stuff->transform); + + nxagentSetPictureTransform(pPicture, &stuff->transform); + + if (client->noClientException != Success) + return(client->noClientException); + else + return(result); +} + +static int +ProcRenderSetPictureFilter (ClientPtr client) +{ + REQUEST (xRenderSetPictureFilterReq); + PicturePtr pPicture; + int result; + xFixed *params; + int nparams; + char *name; + + REQUEST_AT_LEAST_SIZE (xRenderSetPictureFilterReq); + VERIFY_PICTURE (pPicture, stuff->picture, client, DixWriteAccess, + RenderErrBase + BadPicture); + name = (char *) (stuff + 1); + params = (xFixed *) (name + ((stuff->nbytes + 3) & ~3)); + nparams = ((xFixed *) stuff + client->req_len) - params; + result = SetPictureFilter (pPicture, name, stuff->nbytes, params, nparams); + + nxagentSetPictureFilter(pPicture, name, stuff->nbytes, params, nparams); + + return result; +} + +static int +ProcRenderCreateAnimCursor (ClientPtr client) +{ + REQUEST(xRenderCreateAnimCursorReq); + CursorPtr *cursors; + CARD32 *deltas; + CursorPtr pCursor; + int ncursor; + xAnimCursorElt *elt; + int i; + int ret; + + REQUEST_AT_LEAST_SIZE(xRenderCreateAnimCursorReq); + LEGAL_NEW_RESOURCE(stuff->cid, client); + if (client->req_len & 1) + return BadLength; + ncursor = (client->req_len - (SIZEOF(xRenderCreateAnimCursorReq) >> 2)) >> 1; + cursors = malloc (ncursor * (sizeof (CursorPtr) + sizeof (CARD32))); + if (!cursors) + return BadAlloc; + deltas = (CARD32 *) (cursors + ncursor); + elt = (xAnimCursorElt *) (stuff + 1); + for (i = 0; i < ncursor; i++) + { + cursors[i] = (CursorPtr)SecurityLookupIDByType(client, elt->cursor, + RT_CURSOR, DixReadAccess); + if (!cursors[i]) + { + free (cursors); + client->errorValue = elt->cursor; + return BadCursor; + } + deltas[i] = elt->delay; + elt++; + } + ret = AnimCursorCreate (cursors, deltas, ncursor, &pCursor); + free (cursors); + if (ret != Success) + return ret; + + nxagentAnimCursorBits = pCursor -> bits; + + for (i = 0; i < MAXSCREENS; i++) + { + pCursor -> devPriv[i] = NULL; + } + + if (AddResource (stuff->cid, RT_CURSOR, (void *)pCursor)) + return client->noClientException; + return BadAlloc; +} + +static int ProcRenderCreateSolidFill(ClientPtr client) +{ + PicturePtr pPicture; + int error = 0; + REQUEST(xRenderCreateSolidFillReq); + + REQUEST_AT_LEAST_SIZE(xRenderCreateSolidFillReq); + + LEGAL_NEW_RESOURCE(stuff->pid, client); + + pPicture = CreateSolidPicture(stuff->pid, &stuff->color, &error); + if (!pPicture) + return error; + /* AGENT SERVER */ + + nxagentRenderCreateSolidFill(pPicture, &stuff -> color); + + /* AGENT SERVER */ + if (!AddResource (stuff->pid, PictureType, (void *)pPicture)) + return BadAlloc; + return Success; +} + +static int ProcRenderCreateLinearGradient (ClientPtr client) +{ + PicturePtr pPicture; + int len; + int error = 0; + xFixed *stops; + xRenderColor *colors; + REQUEST(xRenderCreateLinearGradientReq); + + REQUEST_AT_LEAST_SIZE(xRenderCreateLinearGradientReq); + + LEGAL_NEW_RESOURCE(stuff->pid, client); + + len = (client->req_len << 2) - sizeof(xRenderCreateLinearGradientReq); + if (stuff->nStops > UINT32_MAX/(sizeof(xFixed) + sizeof(xRenderColor))) + return BadLength; + if (len != stuff->nStops*(sizeof(xFixed) + sizeof(xRenderColor))) + return BadLength; + + stops = (xFixed *)(stuff + 1); + colors = (xRenderColor *)(stops + stuff->nStops); + + pPicture = CreateLinearGradientPicture (stuff->pid, &stuff->p1, &stuff->p2, + stuff->nStops, stops, colors, &error); + if (!pPicture) + return error; + /* AGENT SERVER */ + + nxagentRenderCreateLinearGradient(pPicture, &stuff->p1, &stuff->p2, + stuff->nStops, stops, colors); + + /* AGENT SERVER */ + if (!AddResource (stuff->pid, PictureType, (void *)pPicture)) + return BadAlloc; + return Success; +} + +static int ProcRenderCreateRadialGradient (ClientPtr client) +{ + PicturePtr pPicture; + int len; + int error = 0; + xFixed *stops; + xRenderColor *colors; + REQUEST(xRenderCreateRadialGradientReq); + + REQUEST_AT_LEAST_SIZE(xRenderCreateRadialGradientReq); + + LEGAL_NEW_RESOURCE(stuff->pid, client); + + len = (client->req_len << 2) - sizeof(xRenderCreateRadialGradientReq); + if (len != stuff->nStops*(sizeof(xFixed) + sizeof(xRenderColor))) + return BadLength; + + stops = (xFixed *)(stuff + 1); + colors = (xRenderColor *)(stops + stuff->nStops); + + pPicture = CreateRadialGradientPicture (stuff->pid, &stuff->inner, &stuff->outer, + stuff->inner_radius, stuff->outer_radius, + stuff->nStops, stops, colors, &error); + if (!pPicture) + return error; + /* AGENT SERVER */ + + nxagentRenderCreateRadialGradient(pPicture, &stuff->inner, &stuff->outer, + stuff->inner_radius, + stuff->outer_radius, + stuff->nStops, stops, colors); + + /* AGENT SERVER */ + if (!AddResource (stuff->pid, PictureType, (void *)pPicture)) + return BadAlloc; + return Success; +} + +static int ProcRenderCreateConicalGradient (ClientPtr client) +{ + PicturePtr pPicture; + int len; + int error = 0; + xFixed *stops; + xRenderColor *colors; + REQUEST(xRenderCreateConicalGradientReq); + + REQUEST_AT_LEAST_SIZE(xRenderCreateConicalGradientReq); + + LEGAL_NEW_RESOURCE(stuff->pid, client); + + len = (client->req_len << 2) - sizeof(xRenderCreateConicalGradientReq); + if (len != stuff->nStops*(sizeof(xFixed) + sizeof(xRenderColor))) + return BadLength; + + stops = (xFixed *)(stuff + 1); + colors = (xRenderColor *)(stops + stuff->nStops); + + pPicture = CreateConicalGradientPicture (stuff->pid, &stuff->center, stuff->angle, + stuff->nStops, stops, colors, &error); + if (!pPicture) + return error; + /* AGENT SERVER */ + + nxagentRenderCreateConicalGradient(pPicture, &stuff->center, + stuff->angle, stuff->nStops, stops, + colors); + + /* AGENT SERVER */ + if (!AddResource (stuff->pid, PictureType, (void *)pPicture)) + return BadAlloc; + return Success; +} + + +static int +ProcRenderDispatch (ClientPtr client) +{ + int result; + + REQUEST(xReq); + + /* + * Let the client fail if we are + * hiding the RENDER extension. + */ + + if (nxagentRenderTrap) + { + return BadRequest; + } + + if (stuff->data < RenderNumberRequests) + { + #ifdef TEST + fprintf(stderr, "ProcRenderDispatch: Request [%s] OPCODE#%d.\n", + nxagentRenderRequestLiteral[stuff->data], stuff->data); + #endif + + /* + * Set the nxagentGCTrap flag while + * dispatching a render operation to + * avoid reentrancy in GCOps.c. + */ + + nxagentGCTrap = 1; + + result = (*ProcRenderVector[stuff->data]) (client); + + nxagentGCTrap = 0; + + return result; + } + else + return BadRequest; +} + +static int +SProcRenderDispatch (ClientPtr client) +{ + int result; + + REQUEST(xReq); + + /* + * Let the client fail if we are + * hiding the RENDER extension. + */ + + if (nxagentRenderTrap) + { + return BadRequest; + } + + if (stuff->data < RenderNumberRequests) + { + /* + * Set the nxagentGCTrap flag while + * dispatching a render operation to + * avoid reentrancy in GCOps.c. + */ + + nxagentGCTrap = 1; + + result = (*SProcRenderVector[stuff->data]) (client); + + nxagentGCTrap = 0; + + return result; + } + else + return BadRequest; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXresource.c b/nx-X11/programs/Xserver/hw/nxagent/NXresource.c new file mode 100644 index 000000000..a564d84b9 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXresource.c @@ -0,0 +1,595 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/************************************************************ + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +/* $TOG: resource.c /main/41 1998/02/09 14:20:31 kaleb $ */ + +/* Routines to manage various kinds of resources: + * + * CreateNewResourceType, CreateNewResourceClass, InitClientResources, + * FakeClientID, AddResource, FreeResource, FreeClientResources, + * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange + */ + +/* + * A resource ID is a 32 bit quantity, the upper 2 bits of which are + * off-limits for client-visible resources. The next 8 bits are + * used as client ID, and the low 22 bits come from the client. + * A resource ID is "hashed" by extracting and xoring subfields + * (varying with the size of the hash table). + * + * It is sometimes necessary for the server to create an ID that looks + * like it belongs to a client. This ID, however, must not be one + * the client actually can create, or we have the potential for conflict. + * The 31st bit of the ID is reserved for the server's use for this + * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to + * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a + * resource "owned" by the client. + */ + +#include "../../dix/resource.c" + +#include "Agent.h" +#include "Font.h" +#include "Pixmaps.h" +#include "GCs.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#ifdef NXAGENT_SERVER +static int nxagentResChangedFlag = 0; +#endif + +#ifdef NXAGENT_SERVER +int nxagentFindClientResource(int client, RESTYPE type, void * value) +{ + ResourcePtr pResource; + ResourcePtr *resources; + + int i; + + for (i = 0; i < clientTable[client].buckets; i++) + { + resources = clientTable[client].resources; + + for (pResource = resources[i]; pResource; pResource = pResource -> next) + { + if (pResource -> type == type && pResource -> value == value) + { + #ifdef TEST + fprintf(stderr, "nxagentFindClientResource: Found resource [%p] type [%lu] " + "for client [%d].\n", (void *) value, + pResource -> type, client); + #endif + + return 1; + } + } + } + + return 0; +} + +int nxagentSwitchResourceType(int client, RESTYPE type, void * value) +{ + ResourcePtr pResource; + ResourcePtr *resources; + + RESTYPE internalType = 0; + + int i; + + if (type == RT_PIXMAP) + { + internalType = RT_NX_PIXMAP; + } + else if (type == RT_GC) + { + internalType = RT_NX_GC; + } + else if (type == RT_FONT) + { + internalType = RT_NX_FONT; + } + else + { + return 0; + } + + if (client == serverClient -> index) + { + #ifdef TEST + fprintf(stderr, "nxagentSwitchResourceType: Requesting client is [%d]. Skipping the resource switch.\n", + client); + #endif + + return 0; + } + + for (i = 0; i < clientTable[serverClient -> index].buckets; i++) + { + resources = clientTable[serverClient -> index].resources; + + for (pResource = resources[i]; pResource; pResource = pResource -> next) + { + if (pResource -> type == internalType && + pResource -> value == value) + { + #ifdef TEST + fprintf(stderr, "nxagentSwitchResourceType: Changing resource [%p] type from [%lu] to " + "[%lu] for server client [%d].\n", (void *) value, + (unsigned long) pResource -> type, (unsigned long) type, serverClient -> index); + #endif + + FreeResource(pResource -> id, RT_NONE); + + return 1; + } + } + } + + return 0; +} +#endif /* NXAGENT_SERVER */ + +Bool +AddResource(XID id, RESTYPE type, void * value) +{ + int client; + register ClientResourceRec *rrec; + register ResourcePtr res, *head; + + client = CLIENT_ID(id); + rrec = &clientTable[client]; + if (!rrec->buckets) + { + ErrorF("AddResource(%lx, %lx, %lx), client=%d \n", + (unsigned long)id, type, (unsigned long)value, client); + FatalError("client not in use\n"); + } + +#ifdef NXAGENT_SERVER + + nxagentSwitchResourceType(client, type, value); + + #ifdef TEST + fprintf(stderr, "AddResource: Adding resource for client [%d] type [%lu] value [%p] id [%lu].\n", + client, (unsigned long) type, (void *) value, (unsigned long) id); + #endif + +#endif + + if ((rrec->elements >= 4*rrec->buckets) && + (rrec->hashsize < MAXHASHSIZE)) + RebuildTable(client); + head = &rrec->resources[Hash(client, id)]; + res = (ResourcePtr)malloc(sizeof(ResourceRec)); + if (!res) + { + (*DeleteFuncs[type & TypeMask])(value, id); + return FALSE; + } + res->next = *head; + res->id = id; + res->type = type; + res->value = value; + *head = res; + rrec->elements++; + #ifdef NXAGENT_SERVER + nxagentResChangedFlag = 1; + #endif + if (!(id & SERVER_BIT) && (id >= rrec->expectID)) + rrec->expectID = id + 1; + return TRUE; +} + +void +FreeResource(XID id, RESTYPE skipDeleteFuncType) +{ + int cid; + register ResourcePtr res; + register ResourcePtr *prev, *head; + register int *eltptr; + int elements; + Bool gotOne = FALSE; + +#ifdef NXAGENT_SERVER + + #ifdef TEST + fprintf(stderr, "FreeResource: Freeing resource id [%lu].\n", (unsigned long) id); + #endif + +#endif + + if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) + { + head = &clientTable[cid].resources[Hash(cid, id)]; + eltptr = &clientTable[cid].elements; + + prev = head; + while ( (res = *prev) ) + { + if (res->id == id) + { + RESTYPE rtype = res->type; + *prev = res->next; + elements = --*eltptr; + #ifdef NXAGENT_SERVER + nxagentResChangedFlag = 1; + #endif + if (rtype != skipDeleteFuncType) + (*DeleteFuncs[rtype & TypeMask])(res->value, res->id); + free(res); + if (*eltptr != elements) + prev = head; /* prev may no longer be valid */ + gotOne = TRUE; + } + else + prev = &res->next; + } + } + if (!gotOne) + ErrorF("Freeing resource id=%lX which isn't there.\n", + (unsigned long)id); +} + + +void +FreeResourceByType(XID id, RESTYPE type, Bool skipFree) +{ + int cid; + register ResourcePtr res; + register ResourcePtr *prev, *head; + if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) + { + head = &clientTable[cid].resources[Hash(cid, id)]; + + prev = head; + while ( (res = *prev) ) + { + if (res->id == id && res->type == type) + { + *prev = res->next; + #ifdef NXAGENT_SERVER + nxagentResChangedFlag = 1; + #endif + if (!skipFree) + (*DeleteFuncs[type & TypeMask])(res->value, res->id); + free(res); + break; + } + else + prev = &res->next; + } + } +} + +/* Note: if func adds or deletes resources, then func can get called + * more than once for some resources. If func adds new resources, + * func might or might not get called for them. func cannot both + * add and delete an equal number of resources! + */ + +void +FindClientResourcesByType( + ClientPtr client, + RESTYPE type, + FindResType func, + void * cdata +){ + register ResourcePtr *resources; + register ResourcePtr this, next; + int i, elements; + register int *eltptr; + + #ifdef NXAGENT_SERVER + register ResourcePtr **resptr; + #endif + + if (!client) + client = serverClient; + +/* + * If func triggers a resource table + * rebuild then restart the loop. + */ + +#ifdef NXAGENT_SERVER +RestartLoop: +#endif + + resources = clientTable[client->index].resources; + + #ifdef NXAGENT_SERVER + resptr = &clientTable[client->index].resources; + #endif + + eltptr = &clientTable[client->index].elements; + for (i = 0; i < clientTable[client->index].buckets; i++) + { + for (this = resources[i]; this; this = next) + { + next = this->next; + if (!type || this->type == type) { + elements = *eltptr; + + /* + * FIXME: + * It is not safe to let a function change the resource + * table we are reading! + */ + + #ifdef NXAGENT_SERVER + nxagentResChangedFlag = 0; + #endif + (*func)(this->value, this->id, cdata); + + /* + * Avoid that a call to RebuildTable() could invalidate the + * pointer. This is safe enough, because in RebuildTable() + * the new pointer is allocated just before the old one is + * freed, so it can't point to the same address. + */ + + #ifdef NXAGENT_SERVER + if (*resptr != resources) + goto RestartLoop; + #endif + + /* + * It's not enough to check if the number of elements has + * changed, beacause it could happen that the number of + * resources that have been added matches the number of + * the freed ones. + * 'nxagentResChangedFlag' is set if a resource has been + * added or freed. + */ + + #ifdef NXAGENT_SERVER + if (*eltptr != elements || nxagentResChangedFlag) + #else + if (*eltptr != elements) + #endif + next = resources[i]; /* start over */ + } + } + } +} + +void +FindAllClientResources( + ClientPtr client, + FindAllRes func, + void * cdata +){ + register ResourcePtr *resources; + register ResourcePtr this, next; + int i, elements; + register int *eltptr; + + #ifdef NXAGENT_SERVER + register ResourcePtr **resptr; + #endif + + if (!client) + client = serverClient; + +/* + * If func triggers a resource table + * rebuild then restart the loop. + */ + +#ifdef NXAGENT_SERVER +RestartLoop: +#endif + + resources = clientTable[client->index].resources; + + #ifdef NXAGENT_SERVER + resptr = &clientTable[client->index].resources; + #endif + + eltptr = &clientTable[client->index].elements; + for (i = 0; i < clientTable[client->index].buckets; i++) + { + for (this = resources[i]; this; this = next) + { + next = this->next; + elements = *eltptr; + + /* + * FIXME: + * It is not safe to let a function change the resource + * table we are reading! + */ + + #ifdef NXAGENT_SERVER + nxagentResChangedFlag = 0; + #endif + (*func)(this->value, this->id, this->type, cdata); + + /* + * Avoid that a call to RebuildTable() could invalidate the + * pointer. This is safe enough, because in RebuildTable() + * the new pointer is allocated just before the old one is + * freed, so it can't point to the same address. + */ + + #ifdef NXAGENT_SERVER + if (*resptr != resources) + goto RestartLoop; + #endif + + /* + * It's not enough to check if the number of elements has + * changed, beacause it could happen that the number of + * resources that have been added matches the number of + * the freed ones. + * 'nxagentResChangedFlag' is set if a resource has been + * added or freed. + */ + + #ifdef NXAGENT_SERVER + if (*eltptr != elements || nxagentResChangedFlag) + #else + if (*eltptr != elements) + #endif + next = resources[i]; /* start over */ + } + } +} + + +void * +LookupClientResourceComplex( + ClientPtr client, + RESTYPE type, + FindComplexResType func, + void * cdata +){ + ResourcePtr *resources; + ResourcePtr this; + int i; + + #ifdef NXAGENT_SERVER + ResourcePtr **resptr; + Bool res; + #endif + + if (!client) + client = serverClient; + +/* + * If func triggers a resource table + * rebuild then restart the loop. + */ + +#ifdef NXAGENT_SERVER +RestartLoop: +#endif + + resources = clientTable[client->index].resources; + + #ifdef NXAGENT_SERVER + resptr = &clientTable[client->index].resources; + #endif + + for (i = 0; i < clientTable[client->index].buckets; i++) { + for (this = resources[i]; this; this = this->next) { + if (!type || this->type == type) { + #ifdef NXAGENT_SERVER + res = (*func)(this->value, this->id, cdata); + + if (*resptr != resources) + goto RestartLoop; + + if (res) + return this->value; + #else + if((*func)(this->value, this->id, cdata)) + return this->value; + #endif + } + } + } + return NULL; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXshm.c b/nx-X11/programs/Xserver/hw/nxagent/NXshm.c new file mode 100644 index 000000000..2ffca8066 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXshm.c @@ -0,0 +1,547 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/************************************************************ + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +********************************************************/ + +/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */ + + +#include <nx-X11/X.h> +#include "Trap.h" +#include "Agent.h" + +#include "Drawable.h" +#include "Pixmaps.h" + +#include "../../Xext/shm.c" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#ifdef TEST +#include "Literals.h" +#endif + +extern void fbGetImage(DrawablePtr pDrw, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d); + +extern void fbPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *pImage); + +void +ShmExtensionInit(void) +{ + ExtensionEntry *extEntry; + int i; + +#ifdef MUST_CHECK_FOR_SHM_SYSCALL + if (!CheckForShmSyscall()) + { + ErrorF("MIT-SHM extension disabled due to lack of kernel support\n"); + return; + } +#endif + + if (nxagentOption(SharedMemory) == False) + { + return; + } + + sharedPixmaps = xFalse; + pixmapFormat = 0; + { + sharedPixmaps = nxagentOption(SharedPixmaps); + pixmapFormat = shmPixFormat[0]; + for (i = 0; i < screenInfo.numScreens; i++) + { + if (!shmFuncs[i]) + { + #ifdef TEST + fprintf(stderr, "ShmExtensionInit: Registering shmFuncs as miFuncs.\n"); + #endif + shmFuncs[i] = &miFuncs; + } + if (!shmFuncs[i]->CreatePixmap) + sharedPixmaps = xFalse; + if (shmPixFormat[i] && (shmPixFormat[i] != pixmapFormat)) + { + sharedPixmaps = xFalse; + pixmapFormat = 0; + } + } + if (!pixmapFormat) + pixmapFormat = ZPixmap; + if (sharedPixmaps) + { + for (i = 0; i < screenInfo.numScreens; i++) + { + destroyPixmap[i] = screenInfo.screens[i]->DestroyPixmap; + screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap; + } +#ifdef PIXPRIV + shmPixmapPrivate = AllocatePixmapPrivateIndex(); + for (i = 0; i < screenInfo.numScreens; i++) + { + if (!AllocatePixmapPrivate(screenInfo.screens[i], + shmPixmapPrivate, 0)) + return; + } +#endif + } + } + ShmSegType = CreateNewResourceType(ShmDetachSegment); + if (ShmSegType && + (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors, + ProcShmDispatch, SProcShmDispatch, + ShmResetProc, StandardMinorOpcode))) + { + ShmReqCode = (unsigned char)extEntry->base; + ShmCompletionCode = extEntry->eventBase; + BadShmSegCode = extEntry->errorBase; + EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent; + } +} + +static void +miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data) + DrawablePtr dst; + GCPtr pGC; + int depth, w, h, sx, sy, sw, sh, dx, dy; + unsigned int format; + char *data; +{ + PixmapPtr pmap; + GCPtr putGC; + + nxagentShmTrap = 0; + putGC = GetScratchGC(depth, dst->pScreen); + if (!putGC) + { + nxagentShmTrap = 1; + return; + } + pmap = (*dst->pScreen->CreatePixmap)(dst->pScreen, sw, sh, depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pmap) + { + nxagentShmTrap = 1; + FreeScratchGC(putGC); + return; + } + ValidateGC((DrawablePtr)pmap, putGC); + (*putGC->ops->PutImage)((DrawablePtr)pmap, putGC, depth, -sx, -sy, w, h, 0, + (format == XYPixmap) ? XYPixmap : ZPixmap, data); + FreeScratchGC(putGC); + if (format == XYBitmap) + (void)(*pGC->ops->CopyPlane)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh, + dx, dy, 1L); + else + (void)(*pGC->ops->CopyArea)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh, + dx, dy); + (*pmap->drawable.pScreen->DestroyPixmap)(pmap); + nxagentShmTrap = 1; +} + +static void +fbShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data) + DrawablePtr dst; + GCPtr pGC; + int depth, w, h, sx, sy, sw, sh, dx, dy; + unsigned int format; + char *data; +{ + int length; + char *newdata; + extern int nxagentImageLength(int, int, int, int, int); + + #ifdef TEST + fprintf(stderr, "fbShmPutImage: Called with drawable at [%p] GC at [%p] data at [%p].\n", + (void *) dst, (void *) pGC, (void *) data); + #endif + + if ((format == ZPixmap) || (depth == 1)) + { + PixmapPtr pPixmap; + + pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth, + BitsPerPixel(depth), PixmapBytePad(w, depth), (void *)data); + if (!pPixmap) + return; + if (format == XYBitmap) + (void)(*pGC->ops->CopyPlane)((DrawablePtr)pPixmap, dst, pGC, + sx, sy, sw, sh, dx, dy, 1L); + else + (void)(*pGC->ops->CopyArea)((DrawablePtr)pPixmap, dst, pGC, + sx, sy, sw, sh, dx, dy); + + /* + * We updated the internal framebuffer, + * now we want to go on the real X. + */ + + #ifdef TEST + fprintf(stderr, "fbShmPutImage: Realizing the PutImage with depth [%d] " + " format [%d] w [%d] h [%d] sx [%d] sy [%d] sw [%d] " + " sh [%d] dx [%d].\n", depth, format, w, h, + sx, sy, sw, sh, dx); + #endif + + length = nxagentImageLength(sw, sh, format, 0, depth); + + if ((newdata = calloc(1, length)) != NULL) + { + fbGetImage((DrawablePtr) pPixmap, sx, sy, sw, sh, format, AllPlanes, newdata); + (*pGC->ops->PutImage)(dst, pGC, depth, dx, dy, sw, sh, 0, format, newdata); + + free(newdata); + } + else + { + #ifdef WARNING + fprintf(stderr, "fbShmPutImage: WARNING! Data allocation failed.\n"); + #endif + } + + FreeScratchPixmapHeader(pPixmap); + } + else + { + #ifdef TEST + fprintf(stderr, "fbShmPutImage: Calling miShmPutImage().\n"); + #endif + miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, + data); + } +} + +static int +ProcShmPutImage(client) + register ClientPtr client; +{ + register GCPtr pGC; + register DrawablePtr pDraw; + long length; + ShmDescPtr shmdesc; + REQUEST(xShmPutImageReq); + + REQUEST_SIZE_MATCH(xShmPutImageReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client); + if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) + return BadValue; + if (stuff->format == XYBitmap) + { + if (stuff->depth != 1) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); + } + else if (stuff->format == XYPixmap) + { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); + length *= stuff->depth; + } + else if (stuff->format == ZPixmap) + { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, stuff->depth); + } + else + { + client->errorValue = stuff->format; + return BadValue; + } + + /* + * There's a potential integer overflow in this check: + * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, + * client); + * the version below ought to avoid it + */ + if (stuff->totalHeight != 0 && + length > (shmdesc->size - stuff->offset)/stuff->totalHeight) { + client->errorValue = stuff->totalWidth; + return BadValue; + } + if (stuff->srcX > stuff->totalWidth) + { + client->errorValue = stuff->srcX; + return BadValue; + } + if (stuff->srcY > stuff->totalHeight) + { + client->errorValue = stuff->srcY; + return BadValue; + } + if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) + { + client->errorValue = stuff->srcWidth; + return BadValue; + } + if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) + { + client->errorValue = stuff->srcHeight; + return BadValue; + } + + #ifdef TEST + fprintf(stderr, "ProcShmPutImage: Format [%d] srcX [%d] srcY [%d], " + "totalWidth [%d] totalHeight [%d]\n", stuff->format, stuff->srcX, + stuff->srcY, stuff->totalWidth, stuff->totalHeight); + #endif + + #ifdef TEST + fprintf(stderr, "ProcShmPutImage: Calling (*shmFuncs[pDraw->pScreen->myNum]->PutImage)().\n"); + #endif + + (*shmFuncs[pDraw->pScreen->myNum]->PutImage)( + pDraw, pGC, stuff->depth, stuff->format, + stuff->totalWidth, stuff->totalHeight, + stuff->srcX, stuff->srcY, + stuff->srcWidth, stuff->srcHeight, + stuff->dstX, stuff->dstY, + shmdesc->addr + stuff->offset); + + if (stuff->sendEvent) + { + xShmCompletionEvent ev; + + memset(&ev, 0, sizeof(xShmCompletionEvent)); + ev.type = ShmCompletionCode; + ev.drawable = stuff->drawable; + ev.sequenceNumber = client->sequence; + ev.minorEvent = X_ShmPutImage; + ev.majorEvent = ShmReqCode; + ev.shmseg = stuff->shmseg; + ev.offset = stuff->offset; + WriteEventsToClient(client, 1, (xEvent *) &ev); + } + + return (client->noClientException); +} + + +static PixmapPtr +fbShmCreatePixmap (pScreen, width, height, depth, addr) + ScreenPtr pScreen; + int width; + int height; + int depth; + char *addr; +{ + register PixmapPtr pPixmap; + + nxagentShmPixmapTrap = 1; + + pPixmap = (*pScreen->CreatePixmap)(pScreen, width, height, depth, 0); + + if (!pPixmap) + { + nxagentShmPixmapTrap = 0; + + return NullPixmap; + } + + #ifdef TEST + fprintf(stderr,"fbShmCreatePixmap: Width [%d] Height [%d] Depth [%d] Hint[%d]\n", width, height, depth, 0); + #endif + + if (!(*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth, + BitsPerPixel(depth), PixmapBytePad(width, depth), (void *)addr)) + { + #ifdef WARNING + fprintf(stderr,"fbShmCreatePixmap: Return Null Pixmap.\n"); + #endif + + (*pScreen->DestroyPixmap)(pPixmap); + + nxagentShmPixmapTrap = 0; + + return NullPixmap; + } + + nxagentShmPixmapTrap = 0; + + return pPixmap; +} + + +static int +ProcShmDispatch (client) + register ClientPtr client; +{ + REQUEST(xReq); + + #ifdef TEST + fprintf(stderr, "ProcShmDispatch: Going to execute operation [%d] for client [%d].\n", + stuff -> data, client -> index); + + if (stuff->data <= X_ShmCreatePixmap) + { + fprintf(stderr, "ProcShmDispatch: Request [%s] OPCODE#%d.\n", + nxagentShmRequestLiteral[stuff->data], stuff->data); + } + #endif + + switch (stuff->data) + { + case X_ShmQueryVersion: + return ProcShmQueryVersion(client); + case X_ShmAttach: + return ProcShmAttach(client); + case X_ShmDetach: + return ProcShmDetach(client); + case X_ShmPutImage: + { + int result; + + #ifdef TEST + fprintf(stderr, "ProcShmDispatch: Going to execute ProcShmPutImage() for client [%d].\n", + client -> index); + #endif + + nxagentShmTrap = 1; + +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + { + result = ProcPanoramiXShmPutImage(client); + + nxagentShmTrap = 0; + + return result; + } +#endif + + result = ProcShmPutImage(client); + + nxagentShmTrap = 0; + + #ifdef TEST + fprintf(stderr, "ProcShmDispatch: Returning from ProcShmPutImage() for client [%d].\n", + client -> index); + #endif + + return result; + } + case X_ShmGetImage: +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + return ProcPanoramiXShmGetImage(client); +#endif + return ProcShmGetImage(client); + case X_ShmCreatePixmap: +#ifdef PANORAMIX + if ( !noPanoramiXExtension ) + return ProcPanoramiXShmCreatePixmap(client); +#endif + return ProcShmCreatePixmap(client); + default: + return BadRequest; + } +} + +static int +SProcShmDispatch (client) + register ClientPtr client; +{ + REQUEST(xReq); + + #ifdef TEST + fprintf(stderr, "SProcShmDispatch: Going to execute operation [%d] for client [%d].\n", + stuff -> data, client -> index); + #endif + + switch (stuff->data) + { + case X_ShmQueryVersion: + return SProcShmQueryVersion(client); + case X_ShmAttach: + return SProcShmAttach(client); + case X_ShmDetach: + return SProcShmDetach(client); + case X_ShmPutImage: + { + int result; + + #ifdef TEST + fprintf(stderr, "SProcShmDispatch: Going to execute SProcShmPutImage() for client [%d].\n", + client -> index); + #endif + + nxagentShmTrap = 1; + + result = SProcShmPutImage(client); + + nxagentShmTrap = 0; + + #ifdef TEST + fprintf(stderr, "SProcShmDispatch: Returning from SProcShmPutImage() for client [%d].\n", + client -> index); + #endif + + return result; + } + case X_ShmGetImage: + return SProcShmGetImage(client); + case X_ShmCreatePixmap: + return SProcShmCreatePixmap(client); + default: + return BadRequest; + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXwindow.c b/nx-X11/programs/Xserver/hw/nxagent/NXwindow.c new file mode 100644 index 000000000..7de25ca28 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXwindow.c @@ -0,0 +1,1127 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + + +#include "selection.h" + +#include "Screen.h" +#include "Options.h" +#include "Atoms.h" +#include "Clipboard.h" +#include "Splash.h" +#include "Rootless.h" +#include "Composite.h" +#include "Drawable.h" +#include "Colormap.h" + +/* prototypes (only MakeRootTile() required here) */ + +static void MakeRootTile(WindowPtr pWin); + +#include "../../dix/window.c" + +extern Bool nxagentWMIsRunning; +extern Bool nxagentScreenTrap; + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +WindowPtr nxagentRootTileWindow; + +void nxagentClearSplash(WindowPtr pW) +{ + ScreenPtr pScreen; + + pScreen = pW->drawable.pScreen; + + if (pW->backgroundState == BackgroundPixmap) + { + (*pScreen->DestroyPixmap)(pW->background.pixmap); + } + + pW->backgroundState = BackgroundPixel; + pW->background.pixel = nxagentLogoBlack; + + (*pScreen->ChangeWindowAttributes)(pW, CWBackPixmap|CWBackPixel); +} + +static void +MakeRootTile(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + GCPtr pGC; + unsigned char back[128]; + int len = BitmapBytePad(sizeof(long)); + register unsigned char *from, *to; + register int i, j; + + pWin->background.pixmap = (*pScreen->CreatePixmap)(pScreen, 4, 4, + pScreen->rootDepth, 0); + + pWin->backgroundState = BackgroundPixmap; + pGC = GetScratchGC(pScreen->rootDepth, pScreen); + if (!pWin->background.pixmap || !pGC) + FatalError("could not create root tile"); + + { + CARD32 attributes[2]; + + attributes[0] = pScreen->whitePixel; + attributes[1] = pScreen->blackPixel; + + (void)ChangeGC(pGC, GCForeground | GCBackground, attributes); + } + + ValidateGC((DrawablePtr)pWin->background.pixmap, pGC); + + from = (screenInfo.bitmapBitOrder == LSBFirst) ? _back_lsb : _back_msb; + to = back; + + for (i = 4; i > 0; i--, from++) + for (j = len; j > 0; j--) + *to++ = *from; + + if (blackRoot) + bzero(back, sizeof(back)); + + (*pGC->ops->PutImage)((DrawablePtr)pWin->background.pixmap, pGC, 1, + 0, 0, len, 4, 0, XYBitmap, (char *)back); + + FreeScratchGC(pGC); + + nxagentRootTileWindow = pWin; +} + +void +InitRootWindow(WindowPtr pWin) +{ + ScreenPtr pScreen; + + #ifdef TEST + fprintf(stderr, "InitRootWindow: Called for window at [%p][%ld] with parent [%p].\n", + (void *) pWin, nxagentWindowPriv(pWin)->window, (void *) pWin -> parent); + #endif + + if (nxagentOption(Rootless)) + { + #ifdef TEST + fprintf(stderr, "InitRootWindow: Assigned agent root to window at [%p][%ld] with parent [%p].\n", + (void *) pWin, nxagentWindowPriv(pWin)->window, (void *) pWin -> parent); + #endif + + nxagentRootlessWindow = pWin; + } + + pScreen = pWin->drawable.pScreen; + + /* + * A root window is created for each screen by main + * and the pointer is saved in screenInfo.screens as + * in the following snippet: + * + * for (i = 0; i < screenInfo.numScreens; i++) + * InitRootWindow(screenInfo.screens[i]->root); + * + * Our root window on the real display was already + * created at the time the screen was opened, so it + * is unclear how this window (or the other window, + * if you prefer) fits in the big picture. + */ + + #ifdef TEST + fprintf(stderr, "InitRootWindow: Going to create window as root at [%p][%ld] with parent [%p].\n", + (void *) pWin, nxagentWindowPriv(pWin)->window, (void *) pWin -> parent); + #endif + + if (!(*pScreen->CreateWindow)(pWin)) + return; /* XXX */ + + #ifdef TEST + fprintf(stderr, "InitRootWindow: Created window as root at [%p][%ld] with parent [%p].\n", + (void *) pWin, nxagentWindowPriv(pWin)->window, (void *) pWin -> parent); + #endif + + (*pScreen->PositionWindow)(pWin, 0, 0); + + pWin->cursorIsNone = FALSE; + pWin->optional->cursor = rootCursor; + rootCursor->refcnt++; + pWin->backingStore = defaultBackingStore; + pWin->forcedBS = (defaultBackingStore != NotUseful); + + #ifdef NXAGENT_SPLASH + /* We SHOULD check for an error value here XXX */ + pWin -> background.pixel = pScreen -> blackPixel; + (*pScreen->ChangeWindowAttributes)(pWin, + CWBackPixel|CWBorderPixel|CWCursor|CWBackingStore); + #else + (*pScreen->ChangeWindowAttributes)(pWin, + CWBackPixmap|CWBorderPixel|CWCursor|CWBackingStore); + #endif + + MakeRootTile(pWin); + + /* + * Map both the root and the default agent window. + */ + + #ifdef TEST + fprintf(stderr, "InitRootWindow: Mapping default windows.\n"); + #endif + + nxagentInitAtoms(pWin); + + nxagentInitClipboard(pWin); + + nxagentMapDefaultWindows(); + + nxagentRedirectDefaultWindows(); + + #ifdef NXAGENT_ARTSD + { + char artsd_port[10]; + int nPort; + extern void nxagentPropagateArtsdProperties(ScreenPtr pScreen, char *port); + nPort = atoi(display) + 7000; + sprintf(artsd_port,"%d", nPort); + nxagentPropagateArtsdProperties(pScreen, artsd_port); + } + #endif +} + +/***** + * DeleteWindow + * Deletes child of window then window itself + * If wid is None, don't send any events + *****/ + +int +DeleteWindow(void * value, XID wid) + { + register WindowPtr pParent; + register WindowPtr pWin = (WindowPtr)value; + xEvent event; + + UnmapWindow(pWin, FALSE); + + CrushTree(pWin); + + pParent = pWin->parent; + if (wid && pParent && SubStrSend(pWin, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = DestroyNotify; + event.u.destroyNotify.window = pWin->drawable.id; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + FreeWindowResources(pWin); + if (pParent) + { + if (pParent->firstChild == pWin) + pParent->firstChild = pWin->nextSib; + if (pParent->lastChild == pWin) + pParent->lastChild = pWin->prevSib; + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + } + + if (pWin -> optional && + pWin -> optional -> colormap && + pWin -> parent) + { + nxagentSetInstalledColormapWindows(pWin -> drawable.pScreen); + } + + free(pWin); + return Success; +} + +/* XXX need to retile border on each window with ParentRelative origin */ +void +ResizeChildrenWinSize(register WindowPtr pWin, int dx, int dy, int dw, int dh) +{ + register ScreenPtr pScreen; + register WindowPtr pSib, pChild; + Bool resized = (dw || dh); + + pScreen = pWin->drawable.pScreen; + + for (pSib = pWin->firstChild; pSib; pSib = pSib->nextSib) + { + if (resized && (pSib->winGravity > NorthWestGravity)) + { + int cwsx, cwsy; + + cwsx = pSib->origin.x; + cwsy = pSib->origin.y; + GravityTranslate (cwsx, cwsy, cwsx - dx, cwsy - dy, dw, dh, + pSib->winGravity, &cwsx, &cwsy); + if (cwsx != pSib->origin.x || cwsy != pSib->origin.y) + { + xEvent event; + + event.u.u.type = GravityNotify; + event.u.gravity.window = pSib->drawable.id; + event.u.gravity.x = cwsx - wBorderWidth (pSib); + event.u.gravity.y = cwsy - wBorderWidth (pSib); + DeliverEvents (pSib, &event, 1, NullWindow); + pSib->origin.x = cwsx; + pSib->origin.y = cwsy; + } + } + pSib->drawable.x = pWin->drawable.x + pSib->origin.x; + pSib->drawable.y = pWin->drawable.y + pSib->origin.y; + SetWinSize (pSib); + SetBorderSize (pSib); + + /* + * Don't force X to move children. It will position them + * according with gravity. + * + * (*pScreen->PositionWindow)(pSib, pSib->drawable.x, pSib->drawable.y); + */ + + /* + * Update pSib privates, as this window is moved by X. + */ + + nxagentAddConfiguredWindow(pSib, CW_Update); + + if ( (pChild = pSib->firstChild) ) + { + while (1) + { + pChild->drawable.x = pChild->parent->drawable.x + + pChild->origin.x; + pChild->drawable.y = pChild->parent->drawable.y + + pChild->origin.y; + SetWinSize (pChild); + SetBorderSize (pChild); + + (*pScreen->PositionWindow)(pChild, pChild->drawable.x, + pChild->drawable.y); + + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pSib)) + pChild = pChild->parent; + if (pChild == pSib) + break; + pChild = pChild->nextSib; + } + } + } +} + +/***** + * ConfigureWindow + *****/ + +int +ConfigureWindow(register WindowPtr pWin, register Mask mask, XID *vlist, ClientPtr client) +{ +#define RESTACK_WIN 0 +#define MOVE_WIN 1 +#define RESIZE_WIN 2 +#define REBORDER_WIN 3 + register WindowPtr pSib = NullWindow; + register WindowPtr pParent = pWin->parent; + Window sibwid = 0; + Mask index2, tmask; + register XID *pVlist; + short x, y, beforeX, beforeY; + unsigned short w = pWin->drawable.width, + h = pWin->drawable.height, + bw = pWin->borderWidth; + int action, smode = Above; + xEvent event; + + if ((pWin->drawable.class == InputOnly) && (mask & IllegalInputOnlyConfigureMask)) + return(BadMatch); + + if ((mask & CWSibling) && !(mask & CWStackMode)) + return(BadMatch); + + pVlist = vlist; + + if (pParent) + { + x = pWin->drawable.x - pParent->drawable.x - (int)bw; + y = pWin->drawable.y - pParent->drawable.y - (int)bw; + } + else + { + x = pWin->drawable.x; + y = pWin->drawable.y; + } + beforeX = x; + beforeY = y; + action = RESTACK_WIN; + if ((mask & (CWX | CWY)) && (!(mask & (CWHeight | CWWidth)))) + { + GET_INT16(CWX, x); + GET_INT16(CWY, y); + action = MOVE_WIN; + } + /* or should be resized */ + else if (mask & (CWX | CWY | CWWidth | CWHeight)) + { + GET_INT16(CWX, x); + GET_INT16(CWY, y); + GET_CARD16(CWWidth, w); + GET_CARD16 (CWHeight, h); + if (!w || !h) + { + client->errorValue = 0; + return BadValue; + } + action = RESIZE_WIN; + } + tmask = mask & ~ChangeMask; + while (tmask) + { + index2 = (Mask)lowbit (tmask); + tmask &= ~index2; + switch (index2) + { + case CWBorderWidth: + GET_CARD16(CWBorderWidth, bw); + break; + case CWSibling: + sibwid = (Window ) *pVlist; + pVlist++; + pSib = (WindowPtr )SecurityLookupIDByType(client, sibwid, + RT_WINDOW, DixReadAccess); + if (!pSib) + { + client->errorValue = sibwid; + return(BadWindow); + } + if (pSib->parent != pParent) + return(BadMatch); + if (pSib == pWin) + return(BadMatch); + break; + case CWStackMode: + GET_CARD8(CWStackMode, smode); + if ((smode != TopIf) && (smode != BottomIf) && + (smode != Opposite) && (smode != Above) && (smode != Below)) + { + client->errorValue = smode; + return(BadValue); + } + break; + default: + client->errorValue = mask; + return(BadValue); + } + } + /* root really can't be reconfigured, so just return */ + if (!pParent) + return Success; + + /* Figure out if the window should be moved. Doesnt + make the changes to the window if event sent */ + + #ifdef TEST + if (nxagentWindowTopLevel(pWin)) + { + + fprintf(stderr, "ConfigureWindow: pWin [%p] mask [%lu] client [%p]\n", + pWin, mask, client); + + fprintf(stderr, "ConfigureWindow: x [%d] y [%d] w [%d] h [%d] CWStackMode [%d] " + "smode [%d] pSib [%p]\n", + x, y, w, h, (mask & CWStackMode) ? 1 : 0, smode, pSib); + } + #endif + + if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin) && + pWin -> overrideRedirect == 0 && + nxagentScreenTrap == 0) + { + nxagentConfigureRootlessWindow(pWin, x, y, w, h, bw, pSib, smode, mask); + + return Success; + } + + if (mask & CWStackMode) + pSib = WhereDoIGoInTheStack(pWin, pSib, pParent->drawable.x + x, + pParent->drawable.y + y, + w + (bw << 1), h + (bw << 1), smode); + else + pSib = pWin->nextSib; + + + if ((!pWin->overrideRedirect) && + (RedirectSend(pParent) + )) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = ConfigureRequest; + event.u.configureRequest.window = pWin->drawable.id; + if (mask & CWSibling) + event.u.configureRequest.sibling = sibwid; + else + event.u.configureRequest.sibling = None; + if (mask & CWStackMode) + event.u.u.detail = smode; + else + event.u.u.detail = Above; + event.u.configureRequest.x = x; + event.u.configureRequest.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { + event.u.configureRequest.x += panoramiXdataPtr[0].x; + event.u.configureRequest.y += panoramiXdataPtr[0].y; + } +#endif + event.u.configureRequest.width = w; + event.u.configureRequest.height = h; + event.u.configureRequest.borderWidth = bw; + event.u.configureRequest.valueMask = mask; + event.u.configureRequest.parent = pParent->drawable.id; + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return(Success); + } + if (action == RESIZE_WIN) + { + Bool size_change = (w != pWin->drawable.width) + || (h != pWin->drawable.height); + if (size_change && ((pWin->eventMask|wOtherEventMasks(pWin)) & ResizeRedirectMask)) + { + xEvent eventT; + memset(&eventT, 0, sizeof(xEvent)); + eventT.u.u.type = ResizeRequest; + eventT.u.resizeRequest.window = pWin->drawable.id; + eventT.u.resizeRequest.width = w; + eventT.u.resizeRequest.height = h; + if (MaybeDeliverEventsToClient(pWin, &eventT, 1, + ResizeRedirectMask, client) == 1) + { + /* if event is delivered, leave the actual size alone. */ + w = pWin->drawable.width; + h = pWin->drawable.height; + size_change = FALSE; + } + } + if (!size_change) + { + if (mask & (CWX | CWY)) + action = MOVE_WIN; + else if (mask & (CWStackMode | CWBorderWidth)) + action = RESTACK_WIN; + else /* really nothing to do */ + return(Success) ; + } + } + + if (action == RESIZE_WIN) + /* we've already checked whether there's really a size change */ + goto ActuallyDoSomething; + if ((mask & CWX) && (x != beforeX)) + goto ActuallyDoSomething; + if ((mask & CWY) && (y != beforeY)) + goto ActuallyDoSomething; + if ((mask & CWBorderWidth) && (bw != wBorderWidth (pWin))) + goto ActuallyDoSomething; + if (mask & CWStackMode) + { +#ifndef ROOTLESS + /* See above for why we always reorder in rootless mode. */ + if (pWin->nextSib != pSib) +#endif + goto ActuallyDoSomething; + } + return(Success); + +ActuallyDoSomething: + if (SubStrSend(pWin, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = ConfigureNotify; + event.u.configureNotify.window = pWin->drawable.id; + if (pSib) + event.u.configureNotify.aboveSibling = pSib->drawable.id; + else + event.u.configureNotify.aboveSibling = None; + event.u.configureNotify.x = x; + event.u.configureNotify.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { + event.u.configureNotify.x += panoramiXdataPtr[0].x; + event.u.configureNotify.y += panoramiXdataPtr[0].y; + } +#endif + event.u.configureNotify.width = w; + event.u.configureNotify.height = h; + event.u.configureNotify.borderWidth = bw; + event.u.configureNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + if (mask & CWBorderWidth) + { + if (action == RESTACK_WIN) + { + action = MOVE_WIN; + pWin->borderWidth = bw; + } + else if ((action == MOVE_WIN) && + (beforeX + wBorderWidth (pWin) == x + (int)bw) && + (beforeY + wBorderWidth (pWin) == y + (int)bw)) + { + action = REBORDER_WIN; + (*pWin->drawable.pScreen->ChangeBorderWidth)(pWin, bw); + } + else + pWin->borderWidth = bw; + } + if (action == MOVE_WIN) + (*pWin->drawable.pScreen->MoveWindow)(pWin, x, y, pSib, + (mask & CWBorderWidth) ? VTOther : VTMove); + else if (action == RESIZE_WIN) + (*pWin->drawable.pScreen->ResizeWindow)(pWin, x, y, w, h, pSib); + else if (mask & CWStackMode) + ReflectStackChange(pWin, pSib, VTOther); + + if (action != RESTACK_WIN) + CheckCursorConfinement(pWin); + + nxagentFlushConfigureWindow(); + + return(Success); +#undef RESTACK_WIN +#undef MOVE_WIN +#undef RESIZE_WIN +#undef REBORDER_WIN +} + +/***** + * ReparentWindow + *****/ + +int +ReparentWindow(register WindowPtr pWin, register WindowPtr pParent, + int x, int y, ClientPtr client) +{ + WindowPtr pPrev, pPriorParent; + Bool WasMapped = (Bool)(pWin->mapped); + xEvent event; + int bw = wBorderWidth (pWin); + register ScreenPtr pScreen; + + pScreen = pWin->drawable.pScreen; + if (TraverseTree(pWin, CompareWIDs, (void *)&pParent->drawable.id) == WT_STOPWALKING) + return(BadMatch); + if (!MakeWindowOptional(pWin)) + return(BadAlloc); + + if (WasMapped) + UnmapWindow(pWin, FALSE); + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = ReparentNotify; + event.u.reparent.window = pWin->drawable.id; + event.u.reparent.parent = pParent->drawable.id; + event.u.reparent.x = x; + event.u.reparent.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && !pParent->parent) { + event.u.reparent.x += panoramiXdataPtr[0].x; + event.u.reparent.y += panoramiXdataPtr[0].y; + } +#endif + event.u.reparent.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, pParent); + + /* take out of sibling chain */ + + pPriorParent = pPrev = pWin->parent; + if (pPrev->firstChild == pWin) + pPrev->firstChild = pWin->nextSib; + if (pPrev->lastChild == pWin) + pPrev->lastChild = pWin->prevSib; + + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + + /* insert at begining of pParent */ + pWin->parent = pParent; + pPrev = RealChildHead(pParent); + + if (pWin->parent == screenInfo.screens[0]->root) + { + nxagentSetTopLevelEventMask(pWin); + } + + if (pPrev) + { + pWin->nextSib = pPrev->nextSib; + if (pPrev->nextSib) + pPrev->nextSib->prevSib = pWin; + else + pParent->lastChild = pWin; + pPrev->nextSib = pWin; + pWin->prevSib = pPrev; + } + else + { + pWin->nextSib = pParent->firstChild; + pWin->prevSib = NullWindow; + if (pParent->firstChild) + pParent->firstChild->prevSib = pWin; + else + pParent->lastChild = pWin; + pParent->firstChild = pWin; + } + + pWin->origin.x = x + bw; + pWin->origin.y = y + bw; + pWin->drawable.x = x + bw + pParent->drawable.x; + pWin->drawable.y = y + bw + pParent->drawable.y; + + /* clip to parent */ + SetWinSize (pWin); + SetBorderSize (pWin); + + if (pScreen->ReparentWindow) + (*pScreen->ReparentWindow)(pWin, pPriorParent); + + (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); + + ResizeChildrenWinSize(pWin, 0, 0, 0, 0); + + CheckWindowOptionalNeed(pWin); + + if (WasMapped) + MapWindow(pWin, client); + RecalculateDeliverableEvents(pWin); + return(Success); +} + +/***** + * MapWindow + * If some other client has selected SubStructureReDirect on the parent + * and override-redirect is xFalse, then a MapRequest event is generated, + * but the window remains unmapped. Otherwise, the window is mapped and a + * MapNotify event is generated. + *****/ + +int +MapWindow(register WindowPtr pWin, ClientPtr client) +{ + register ScreenPtr pScreen; + + register WindowPtr pParent; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + WindowPtr pLayerWin; + + #ifdef TEST + if (nxagentWindowTopLevel(pWin)) + { + fprintf(stderr, "MapWindow: pWin [%p] client [%p]\n", pWin, client); + } + #endif + + if (pWin->mapped) + return(Success); + +#ifdef XCSECURITY + /* don't let an untrusted client map a child-of-trusted-window, InputOnly + * window; too easy to steal device input + */ + if ( (client->trustLevel != XSecurityClientTrusted) && + (pWin->drawable.class == InputOnly) && + (wClient(pWin->parent)->trustLevel == XSecurityClientTrusted) ) + return Success; +#endif + + pScreen = pWin->drawable.pScreen; + if ( (pParent = pWin->parent) ) + { + xEvent event; + Bool anyMarked; + + if ((!pWin->overrideRedirect) && + (RedirectSend(pParent) + )) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapRequest; + event.u.mapRequest.window = pWin->drawable.id; + event.u.mapRequest.parent = pParent->drawable.id; + + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return(Success); + } + + pWin->mapped = TRUE; + if (SubStrSend(pWin, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapNotify; + event.u.mapNotify.window = pWin->drawable.id; + event.u.mapNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + if (!pParent->realized) + return(Success); + RealizeTree(pWin); + if (pWin->viewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pWin->nextSib); + } +#endif /* DO_SAVE_UNDERS */ + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTMap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pLayerWin, pWin->nextSib); +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, VTMap); + } + WindowsRestructured (); + } + else + { + RegionRec temp; + + pWin->mapped = TRUE; + pWin->realized = TRUE; /* for roots */ + pWin->viewable = pWin->drawable.class == InputOutput; + /* We SHOULD check for an error value here XXX */ + (*pScreen->RealizeWindow)(pWin); + if (pScreen->ClipNotify) + (*pScreen->ClipNotify) (pWin, 0, 0); + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(NullWindow, pWin, VTMap); + RegionNull(&temp); + RegionCopy(&temp, &pWin->clipList); + (*pScreen->WindowExposures) (pWin, &temp, NullRegion); + RegionUninit(&temp); + } + + nxagentFlushConfigureWindow(); + + return(Success); +} + +/***** + * UnmapWindow + * If the window is already unmapped, this request has no effect. + * Otherwise, the window is unmapped and an UnMapNotify event is + * generated. Cannot unmap a root window. + *****/ + +int +UnmapWindow(register WindowPtr pWin, Bool fromConfigure) +{ + register WindowPtr pParent; + xEvent event; + Bool wasRealized = (Bool)pWin->realized; + Bool wasViewable = (Bool)pWin->viewable; + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pLayerWin = pWin; + + #ifdef TEST + if (nxagentWindowTopLevel(pWin)) + { + fprintf(stderr, "UnmapWindow: pWin [%p] fromConfigure [%d]\n", pWin, + fromConfigure); + } + #endif + + if ((!pWin->mapped) || (!(pParent = pWin->parent))) + return(Success); + if (SubStrSend(pWin, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = UnmapNotify; + event.u.unmapNotify.window = pWin->drawable.id; + event.u.unmapNotify.fromConfigure = fromConfigure; + DeliverEvents(pWin, &event, 1, NullWindow); + } + if (wasViewable && !fromConfigure) + { + pWin->valdata = UnmapValData; + (*pScreen->MarkOverlappedWindows)(pWin, pWin->nextSib, &pLayerWin); + (*pScreen->MarkWindow)(pLayerWin->parent); + } + pWin->mapped = FALSE; + if (wasRealized) + UnrealizeTree(pWin, fromConfigure); + if (wasViewable) + { + if (!fromConfigure) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pWin, VTUnmap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + if ( (*pScreen->ChangeSaveUnder)(pLayerWin, pWin->nextSib) ) + { + (*pScreen->PostChangeSaveUnder)(pLayerWin, pWin->nextSib); + } + } + pWin->DIXsaveUnder = FALSE; +#endif /* DO_SAVE_UNDERS */ + if (!fromConfigure && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap); + } + if (wasRealized && !fromConfigure) + WindowsRestructured (); + return(Success); +} + +void +SaveScreens(int on, int mode) +{ + int i; + int what; + int type; + + if (on == SCREEN_SAVER_FORCER) + { + UpdateCurrentTimeIf(); + lastDeviceEventTime = currentTime; + if (mode == ScreenSaverReset) + what = SCREEN_SAVER_OFF; + else + what = SCREEN_SAVER_ON; + type = what; + } + else + { + what = on; + type = what; + if (what == screenIsSaved) + type = SCREEN_SAVER_CYCLE; + } + for (i = 0; i < screenInfo.numScreens; i++) + { + if (on == SCREEN_SAVER_FORCER) + (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], on); + if (savedScreenInfo[i].ExternalScreenSaver) + { + if (nxagentOption(Timeout) != 0) + { + #ifdef TEST + fprintf(stderr, "SaveScreens: An external screen-saver handler is installed. " + "Ignoring it to let the auto-disconnect feature work.\n"); + #endif + } + else + { + if ((*savedScreenInfo[i].ExternalScreenSaver) + (screenInfo.screens[i], type, on == SCREEN_SAVER_FORCER)) + continue; + } + } + if (type == screenIsSaved) + continue; + switch (type) { + case SCREEN_SAVER_OFF: + if (savedScreenInfo[i].blanked == SCREEN_IS_BLANKED) + { + (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], + what); + } + else if (HasSaverWindow (i)) + { + savedScreenInfo[i].pWindow = NullWindow; + FreeResource(savedScreenInfo[i].wid, RT_NONE); + } + break; + case SCREEN_SAVER_CYCLE: + if (savedScreenInfo[i].blanked == SCREEN_IS_TILED) + { + WindowPtr pWin = savedScreenInfo[i].pWindow; + /* make it look like screen saver is off, so that + * NotClippedByChildren will compute a clip list + * for the root window, so miPaintWindow works + */ + screenIsSaved = SCREEN_SAVER_OFF; +#ifndef NOLOGOHACK + if (logoScreenSaver) + (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, FALSE); +#endif + (*pWin->drawable.pScreen->MoveWindow)(pWin, + (short)(-(rand() % RANDOM_WIDTH)), + (short)(-(rand() % RANDOM_WIDTH)), + pWin->nextSib, VTMove); +#ifndef NOLOGOHACK + if (logoScreenSaver) + DrawLogo(pWin); +#endif + screenIsSaved = SCREEN_SAVER_ON; + } + /* + * Call the DDX saver in case it wants to do something + * at cycle time + */ + else if (savedScreenInfo[i].blanked == SCREEN_IS_BLANKED) + { + (* screenInfo.screens[i]->SaveScreen) (screenInfo.screens[i], + type); + } + break; + case SCREEN_SAVER_ON: + if (ScreenSaverBlanking != DontPreferBlanking) + { + if ((* screenInfo.screens[i]->SaveScreen) + (screenInfo.screens[i], what)) + { + savedScreenInfo[i].blanked = SCREEN_IS_BLANKED; + continue; + } + if ((ScreenSaverAllowExposures != DontAllowExposures) && + TileScreenSaver(i, SCREEN_IS_BLACK)) + { + savedScreenInfo[i].blanked = SCREEN_IS_BLACK; + continue; + } + } + if ((ScreenSaverAllowExposures != DontAllowExposures) && + TileScreenSaver(i, SCREEN_IS_TILED)) + { + savedScreenInfo[i].blanked = SCREEN_IS_TILED; + } + else + savedScreenInfo[i].blanked = SCREEN_ISNT_SAVED; + break; + } + } + screenIsSaved = what; + if (mode == ScreenSaverReset) + SetScreenSaverTimer(); +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/NXxvdisp.c b/nx-X11/programs/Xserver/hw/nxagent/NXxvdisp.c new file mode 100644 index 000000000..ee19c28d0 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/NXxvdisp.c @@ -0,0 +1,245 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/*********************************************************** +Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts, +and the Massachusetts Institute of Technology, Cambridge, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or MIT not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#if !defined(__sun) && !defined(__CYGWIN__) + +#include "Trap.h" + +#include "../../Xext/xvdisp.c" + +#undef TEST +#undef DEBUG + +/* +** ProcXvDispatch +** +** +** +*/ + +int +ProcXvDispatch(ClientPtr client) +{ + int result; + + REQUEST(xReq); + + UpdateCurrentTime(); + + /* + * Report upstream that we are + * dispatching a XVideo operation. + */ + + nxagentXvTrap = 1; + + #ifdef TEST + fprintf(stderr, "ProcXvDispatch: Going to dispatch XVideo operation [%d] for client [%d].\n", + stuff->data, client -> index); + #endif + + switch (stuff->data) + { + case xv_QueryExtension: result = (ProcXvQueryExtension(client)); break; + case xv_QueryAdaptors: result = (ProcXvQueryAdaptors(client)); break; + case xv_QueryEncodings: result = (ProcXvQueryEncodings(client)); break; + case xv_PutVideo: +#ifdef PANORAMIX + if(!noPanoramiXExtension) + result = (XineramaXvPutVideo(client)); + else +#endif + result = (ProcXvPutVideo(client)); + break; + case xv_PutStill: +#ifdef PANORAMIX + if(!noPanoramiXExtension) + result = (XineramaXvPutStill(client)); + else +#endif + result = (ProcXvPutStill(client)); + break; + case xv_GetVideo: result = (ProcXvGetVideo(client)); break; + case xv_GetStill: result = (ProcXvGetStill(client)); break; + case xv_GrabPort: result = (ProcXvGrabPort(client)); break; + case xv_UngrabPort: result = (ProcXvUngrabPort(client)); break; + case xv_SelectVideoNotify: result = (ProcXvSelectVideoNotify(client)); break; + case xv_SelectPortNotify: result = (ProcXvSelectPortNotify(client)); break; + case xv_StopVideo: +#ifdef PANORAMIX + if(!noPanoramiXExtension) + result = (XineramaXvStopVideo(client)); + else +#endif + result = (ProcXvStopVideo(client)); + break; + case xv_SetPortAttribute: +#ifdef PANORAMIX + if(!noPanoramiXExtension) + result = (XineramaXvSetPortAttribute(client)); + else +#endif + result = (ProcXvSetPortAttribute(client)); + break; + case xv_GetPortAttribute: result = (ProcXvGetPortAttribute(client)); break; + case xv_QueryBestSize: result = (ProcXvQueryBestSize(client)); break; + case xv_QueryPortAttributes: result = (ProcXvQueryPortAttributes(client)); break; + case xv_PutImage: +#ifdef PANORAMIX + if(!noPanoramiXExtension) + result = (XineramaXvPutImage(client)); + else +#endif + result = (ProcXvPutImage(client)); + break; +#ifdef MITSHM + case xv_ShmPutImage: +#ifdef PANORAMIX + if(!noPanoramiXExtension) + result = (XineramaXvShmPutImage(client)); + else +#endif + result = (ProcXvShmPutImage(client)); + break; +#endif + case xv_QueryImageAttributes: result = (ProcXvQueryImageAttributes(client)); break; + case xv_ListImageFormats: result = (ProcXvListImageFormats(client)); break; + default: + if (stuff->data < xvNumRequests) + { + SendErrorToClient(client, XvReqCode, stuff->data, 0, + BadImplementation); + result = (BadImplementation); break; + } + else + { + SendErrorToClient(client, XvReqCode, stuff->data, 0, BadRequest); + result = (BadRequest); break; + } + } + + nxagentXvTrap = 0; + + #ifdef TEST + fprintf(stderr, "ProcXvDispatch: Dispatched XVideo operation [%d] for client [%d].\n", + stuff->data, client -> index); + #endif + + return result; +} + +int +SProcXvDispatch(ClientPtr client) +{ + int result; + + REQUEST(xReq); + + UpdateCurrentTime(); + + /* + * Report upstream that we are + * dispatching a XVideo operation. + */ + + nxagentXvTrap = 1; + + #ifdef TEST + fprintf(stderr, "SProcXvDispatch: Going to dispatch XVideo operation [%d] for client [%d].\n", + stuff->data, client -> index); + #endif + + switch (stuff->data) + { + case xv_QueryExtension: result = (SProcXvQueryExtension(client)); break; + case xv_QueryAdaptors: result = (SProcXvQueryAdaptors(client)); break; + case xv_QueryEncodings: result = (SProcXvQueryEncodings(client)); break; + case xv_PutVideo: result = (SProcXvPutVideo(client)); break; + case xv_PutStill: result = (SProcXvPutStill(client)); break; + case xv_GetVideo: result = (SProcXvGetVideo(client)); break; + case xv_GetStill: result = (SProcXvGetStill(client)); break; + case xv_GrabPort: result = (SProcXvGrabPort(client)); break; + case xv_UngrabPort: result = (SProcXvUngrabPort(client)); break; + case xv_SelectVideoNotify: result = (SProcXvSelectVideoNotify(client)); break; + case xv_SelectPortNotify: result = (SProcXvSelectPortNotify(client)); break; + case xv_StopVideo: result = (SProcXvStopVideo(client)); break; + case xv_SetPortAttribute: result = (SProcXvSetPortAttribute(client)); break; + case xv_GetPortAttribute: result = (SProcXvGetPortAttribute(client)); break; + case xv_QueryBestSize: result = (SProcXvQueryBestSize(client)); break; + case xv_QueryPortAttributes: result = (SProcXvQueryPortAttributes(client)); break; + case xv_PutImage: result = (SProcXvPutImage(client)); break; +#ifdef MITSHM + case xv_ShmPutImage: result = (SProcXvShmPutImage(client)); break; +#endif + case xv_QueryImageAttributes: result = (SProcXvQueryImageAttributes(client)); break; + case xv_ListImageFormats: result = (SProcXvListImageFormats(client)); break; + default: + if (stuff->data < xvNumRequests) + { + SendErrorToClient(client, XvReqCode, stuff->data, 0, + BadImplementation); + result = (BadImplementation); break; + } + else + { + SendErrorToClient(client, XvReqCode, stuff->data, 0, BadRequest); + result = (BadRequest); break; + } + } + + nxagentXvTrap = 0; + + #ifdef TEST + fprintf(stderr, "ProcXvDispatch: Dispatched XVideo operation [%d] for client [%d].\n", + stuff->data, client -> index); + #endif + + return result; +} +#endif /* !defined(__sun) && !defined(__CYGWIN__) */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.c b/nx-X11/programs/Xserver/hw/nxagent/Options.c new file mode 100644 index 000000000..978f3ab95 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Options.c @@ -0,0 +1,210 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#include "X.h" + +#include "Agent.h" +#include "Args.h" +#include "Options.h" +#include "Utils.h" + +/* + * Instead of having a single options repository + * data could be attached to the display or the + * screen. The macro nxagentOption() should make + * the transition simple. + */ + +AgentOptionsRec nxagentOptions; + +AgentOptionsRec nxagentOptionsBackup; + +AgentOptionsPtr nxagentOptionsPtr = &nxagentOptions; + +/* + * If this is set, print the geometry in the block handler. + */ + +unsigned int nxagentPrintGeometryFlags = 0; +/* + * This must be called at startup to initialize + * the options repository to the default values. + */ + +void nxagentInitOptions() +{ + nxagentOptions.LinkType = UNDEFINED; + + nxagentOptions.Desktop = UNDEFINED; + nxagentOptions.Persistent = 1; + nxagentOptions.Rootless = UNDEFINED; + nxagentOptions.Fullscreen = UNDEFINED; + nxagentOptions.NoRootlessExit = False; + + nxagentOptions.X = 0; + nxagentOptions.Y = 0; + nxagentOptions.Width = 0; + nxagentOptions.Height = 0; + nxagentOptions.BorderWidth = 0; + + nxagentOptions.WMBorderWidth = -1; + nxagentOptions.WMTitleHeight = -1; + + nxagentOptions.SavedX = 0; + nxagentOptions.SavedY = 0; + nxagentOptions.SavedWidth = 0; + nxagentOptions.SavedHeight = 0; + + nxagentOptions.Timeout = 0; + + nxagentOptions.Nested = 0; + + nxagentOptions.BackingStore = BackingStoreUndefined; + + nxagentOptions.Clipboard = ClipboardBoth; + + nxagentOptions.SharedMemory = 1; + + nxagentOptions.SharedPixmaps = 1; + + nxagentOptions.DeviceControl = 0; + + nxagentOptions.DeviceControlUserDefined = 0; + + nxagentOptions.ResetKeyboardAtResume = 1; + + nxagentOptions.Reset = 0; + + nxagentOptions.RootX = 0; + nxagentOptions.RootY = 0; + nxagentOptions.RootWidth = 0; + nxagentOptions.RootHeight = 0; + + nxagentOptions.ViewportXSpan = 0; + nxagentOptions.ViewportYSpan = 0; + + #ifndef __CYGWIN32__ + + nxagentOptions.DesktopResize = 1; + + #else + + nxagentOptions.DesktopResize = 0; + + #endif + + nxagentOptions.Ratio = DONT_SCALE; + nxagentOptions.XRatio = DONT_SCALE; + nxagentOptions.YRatio = DONT_SCALE; + + nxagentOptions.FloatRatio = 1.0; + nxagentOptions.FloatXRatio = 1.0; + nxagentOptions.FloatYRatio = 1.0; + + nxagentOptions.UseDamage = 1; + + nxagentOptions.Binder = UNDEFINED; + nxagentOptions.BinderOptions = NULL; + + nxagentOptions.Xdmcp = 0; + + nxagentOptions.DisplayLatency = 0; + nxagentOptions.DisplayBuffer = UNDEFINED; + nxagentOptions.DisplayCoalescence = 0; + + nxagentOptions.Composite = 1; + + nxagentOptions.IgnoreVisibility = 0; + + nxagentOptions.ViewOnly = 0; + + nxagentOptions.Adaptive = 0; + + nxagentOptions.Streaming = 0; + + nxagentOptions.DeferLevel = UNDEFINED; + nxagentOptions.DeferTimeout = 200; + + nxagentOptions.TileWidth = UNDEFINED; + nxagentOptions.TileHeight = UNDEFINED; + + nxagentOptions.Menu = 1; + + nxagentOptions.ClientOs = UNDEFINED; + + nxagentOptions.InhibitXkb = 1; + + nxagentOptions.CopyBufferSize = COPY_UNLIMITED; + + nxagentOptions.ImageRateLimit = 0; + + nxagentOptions.Xinerama = 1; + + nxagentOptions.SleepTime = DEFAULT_SLEEP_TIME; + + nxagentOptions.ReconnectTolerance = DEFAULT_TOLERANCE; +} + +/* + * This is called at session reconnection + * to reset some options to their default + * values. The reason to avoid calling the + * nxagentInitOptions() is that not all the + * options can change value when reconnec- + * ting. + */ + +void nxagentResetOptions() +{ + if (nxagentLockDeferLevel == 0) + { + nxagentOptions.DeferLevel = UNDEFINED; + } + + nxagentOptions.DeferTimeout = 200; + + nxagentOptions.TileWidth = UNDEFINED; + nxagentOptions.TileHeight = UNDEFINED; + + nxagentOptions.WMBorderWidth = -1; + nxagentOptions.WMTitleHeight = -1; +} + +void nxagentSaveOptions() +{ + memcpy(&nxagentOptionsBackup, &nxagentOptions, sizeof(AgentOptionsRec)); +} + +void nxagentRestoreOptions() +{ + nxagentOptions.DeferLevel = nxagentOptionsBackup.DeferLevel; + nxagentOptions.DeferTimeout = nxagentOptionsBackup.DeferTimeout; + + nxagentOptions.TileWidth = nxagentOptionsBackup.TileWidth; + nxagentOptions.TileHeight = nxagentOptionsBackup.TileHeight; +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Options.h b/nx-X11/programs/Xserver/hw/nxagent/Options.h new file mode 100644 index 000000000..20616a90b --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Options.h @@ -0,0 +1,479 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Options_H__ +#define __Options_H__ + +#ifndef True +#define True 1 +#endif + +#ifndef False +#define False 0 +#endif + +#define UNDEFINED -1 +#define COPY_UNLIMITED -1 +#define DEFAULT_SLEEP_TIME 50 + +extern unsigned int nxagentPrintGeometryFlags; + +typedef enum _BackingStoreMode +{ + BackingStoreUndefined = -1, + BackingStoreNever, + BackingStoreWhenRequested, + BackingStoreForce + +} BackingStoreMode; + +typedef enum _ClipboardMode +{ + ClipboardBoth, + ClipboardClient, + ClipboardServer, + ClipboardNone + +} ClipboardMode; + +typedef enum _ClientOsType +{ + ClientOsWinnt = 0, + ClientOsLinux, + ClientOsSolaris, + ClientOsMac + +} ClientOsType; + +typedef enum _ToleranceChecksMode +{ + ToleranceChecksStrict = 0, + ToleranceChecksSafe = 1, + ToleranceChecksRisky = 2, + ToleranceChecksBypass = 3 +} ToleranceChecksMode; + + +#define DEFAULT_TOLERANCE ToleranceChecksStrict + +/* + * Set of options affecting agent operations. + */ + +typedef struct _AgentOptions +{ + /* + * Link type of the NX connection or none, + * if this is a direct X11 connection. + */ + + int LinkType; + + /* + * Is agent running in desktop mode? This + * is presently the default. + */ + + int Desktop; + + /* + * True if user activated rootless mode. + */ + + int Rootless; + + /* + * True for shadow mode. + */ + + int Shadow; + + /* + * True if user activated persistent mode. + */ + + int Persistent; + + /* + * True if user activated fullscreen mode. + */ + + int Fullscreen; + + /* + * True if the fullscreen NX session will + * extend on all available screens. + */ + + int AllScreens; + + /* + * Set to the auto-disconnect timeout, if + * the user activated this feature. + */ + + int Timeout; + + /* + * Geometry of the agent's window. + */ + + int X; + int Y; + int Width; + int Height; + int BorderWidth; + + /* + * Geometry of the agent's window in window + * mode. Used to restore window size when + * switching back to window mode from full- + * screen. + */ + + int WMBorderWidth; + int WMTitleHeight; + + int SavedX; + int SavedY; + int SavedWidth; + int SavedHeight; + + int SavedRootWidth; + int SavedRootHeight; + + /* + * Set if agent is running nested in another + * agent X server. + */ + + int Nested; + + /* + * Selected backing-store mode. + */ + + BackingStoreMode BackingStore; + + /* + * Selected clipboard mode. + */ + + ClipboardMode Clipboard; + + /* + * Enable agent to use the MITSHM extension in + * path from remote proxy to the real X server. + */ + + int SharedMemory; + + /* + * Enable agent to use shared Pixmaps + */ + + int SharedPixmaps; + + /* + * Enable agent to propagate keyboard and pointer + * device configuration to the remote X server. + */ + + int DeviceControl; + + /* + * Explicitly asked config propagation. + */ + + int DeviceControlUserDefined; + + /* + * Resuming keyboard device corrects keymap if session + * migrates across platforms with different keycode + * layout. + */ + + int ResetKeyboardAtResume; + + /* + * Reset server when the last client disconnects. + */ + + int Reset; + + /* + * Geometry of the agent root window, relative to + * the agent default window. + */ + + int RootX; + int RootY; + int RootWidth; + int RootHeight; + + /* + * Horizontal and vertical span of the + * agent viewport. + */ + + int ViewportXSpan; + int ViewportYSpan; + + /* + * True if the user can resize the desktop + * by dragging the window border. + */ + + int DesktopResize; + + /* + * The scaling ratio of the shadow agent. + */ + + int Ratio; + + int XRatio; + + int YRatio; + + float FloatRatio; + + float FloatXRatio; + + float FloatYRatio; + + /* + * The shadow agent uses the Damage extension. + */ + + int UseDamage; + + /* + * Was the agent run with the -B option? + */ + + int Binder; + + char *BinderOptions; + + /* + * Set if the agent has to connect to a + * desktop manager to start the session. + */ + + int Xdmcp; + + /* + * Latency of the link. It is simply set + * to a reference value, calculated based + * on the time required to complete the + * query of the agent's atoms at session + * startup. + */ + + int DisplayLatency; + + /* + * Size of the Xlib display buffer. The + * default is set according to the link + * type. + */ + + int DisplayBuffer; + + /* + * Buffer coalescence timeout. + */ + + int DisplayCoalescence; + + /* + * Use the composite extension when + * available on the remote display. + */ + + int Composite; + + /* + * If set, don't skip internal operations + * when the agent window is not fully visible. + */ + + int IgnoreVisibility; + + /* + * If set, prevent the shadow session to + * interact with master diplay. + */ + + int ViewOnly; + + /* + * If true select a lossy or lossless comp- + * ression method based on the characterist- + * ics of the image. + */ + + int Adaptive; + + /* + * Stream the images and update the display + * when the image has been completely trans- + * ferred. + */ + + int Streaming; + + /* + * Use a lazy approach in updating the remote + * display. This means delaying the bandwidth + * consuming graphic operations and synchroniz- + * ing the screen at idle time. + */ + + int DeferLevel; + + /* + * Maxuimum elapsed time before a new full + * synchronization. + */ + + unsigned long DeferTimeout; + + /* + * Maximum size of the tile used when sending + * an image to the remote display. + */ + + int TileWidth; + int TileHeight; + + /* + * Enabling/disabling the pulldown menu. + */ + + int Menu; + + /* + * Specify the Operative System of the client. + */ + + int ClientOs; + + /* + * Inhibit some XKEYBOARD requests. + */ + + int InhibitXkb; + + /* + * Maximum number of bytes that can be pasted from + * an NX session into an external application. + */ + + int CopyBufferSize; + + /* + * Max image data rate to the encoder input. + */ + + int ImageRateLimit; + + /* + * True if agent should not exit if there are no + * clients in rootless mode + */ + + int NoRootlessExit; + + /* + * Store if the user wants Xinerama. There are variables called + * noPanoramiXExtension and noRRXineramaExtensison in os/utils.c but + * we cannot rely on them because RandR and PanoramiX change their + * values when trying to initialize. So we use this variable to + * save the user preference provided by the -/+(rr)xinerama parameter(s) + * before initalizing those extensions. + */ + + int Xinerama; + + /* + * Sleep delay in microseconds. + */ + + unsigned int SleepTime; + + /* + * Tolerance - tightens or loosens reconnect checks. + */ + + ToleranceChecksMode ReconnectTolerance; + +} AgentOptionsRec; + +typedef AgentOptionsRec *AgentOptionsPtr; + +extern AgentOptionsPtr nxagentOptionsPtr; + +/* + * Macros and functions giving access to options. + */ + +#define nxagentOption(option) \ + (nxagentOptionsPtr -> option) + +#define nxagentChangeOption(option, value) \ + (nxagentOptionsPtr -> option = (value)) + +#define nxagentOptions() \ + (nxagentOptionsPtr) + +/* + * Initialize the options to the default values. + */ + +extern void nxagentInitOptions(void); + +/* + * Initialize some options to the default values + * at reconnection. + */ + +extern void nxagentResetOptions(void); + +/* + * Save a copy of the current option repository. + */ + +extern void nxagentSaveOptions(void); + +/* + * Restore the options reset by nxagentResetOptions + * to their backup value. + */ + +extern void nxagentRestoreOptions(void); + +#endif /* __Options_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Pixels.c b/nx-X11/programs/Xserver/hw/nxagent/Pixels.c new file mode 100644 index 000000000..e59ef97ab --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Pixels.c @@ -0,0 +1,392 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +#include "Xmd.h" +#include "Xlib.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define PIXEL_ELEMENTS 256 +#define PIXEL_THRESHOLD 8 +#define PIXEL_STEP 7 + +unsigned int Get16(const char *buffer, int order); +unsigned int Get24(const char *buffer, int order); +unsigned int Get32(const char *buffer, int order); + +void Put16(unsigned int value, char *buffer, int order); +void Put24(unsigned int value, char *buffer, int order); +void Put32(unsigned int value, char *buffer, int order); + +static int nxagentComparePixels(const void *p1, const void *p2) +{ + int pixel1 = *((int *) p1); + int pixel2 = *((int *) p2); + + return (pixel1 < pixel2 ? -1 : (pixel1 == pixel2 ? 0 : 1)); +} + +int nxagentUniquePixels(XImage *image) +{ + int i = 0; + + int pixels[PIXEL_ELEMENTS]; + + int elements = PIXEL_ELEMENTS; + int unique = 0; + + int total; + int ratio; + int step; + + int last = -1; + + const char *next = image -> data; + + #ifdef TEST + fprintf(stderr, "nxagentUniquePixels: Image geometry [%d,%d] depth [%d] bits per pixel [%d].\n", + image -> width, image -> height, image -> depth, image -> bits_per_pixel); + #endif + + /* + * Take at most 256 pixels from the image. + */ + + total = image -> width * image -> height; + + step = total / elements; + + if (step < PIXEL_STEP) + { + step = PIXEL_STEP; + } + + #ifdef TEST + fprintf(stderr, "nxagentUniquePixels: Step is [%d] with [%d] pixels and [%d] elements.\n", + step, total, elements); + #endif + + /* + * Shift at the left after each scanline. + */ + + if (image -> bytes_per_line % step == 0) + { + step++; + + #ifdef TEST + fprintf(stderr, "nxagentUniquePixels: Increasing step to [%d] with [%d] bytes per line.\n", + step, image -> bytes_per_line); + #endif + } + + elements = total / step; + + if (elements > PIXEL_ELEMENTS) + { + elements = PIXEL_ELEMENTS; + } + + #ifdef TEST + fprintf(stderr, "nxagentUniquePixels: Step is now [%d] with [%d] elements.\n", + step, elements); + #endif + + if (elements < PIXEL_THRESHOLD) + { + #ifdef TEST + fprintf(stderr, "nxagentUniquePixels: Assuming ratio [100] with only [%d] elements.\n", + elements); + #endif + + return 100; + } + + #ifdef TEST + fprintf(stderr, "nxagentUniquePixels: Scanning [%d] pixels out of [%d] with step [%d].\n", + elements, total, step); + #endif + + /* + * Take one pixel every n from the image and + * add it to the array. + */ + + switch (image -> bits_per_pixel) + { + case 32: + { + for (i = 0; i < elements; i++) + { + pixels[i] = Get32(next, image -> byte_order); + + next += (4 * step); + + #ifdef DEBUG + fprintf(stderr, "nxagentUniquePixels: pixels[%d][0x%08x].\n", + i, pixels[i]); + #endif + } + + break; + } + case 24: + { + for (i = 0; i < elements; i++) + { + pixels[i] = Get24(next, image -> byte_order); + + next += (3 * step); + + #ifdef DEBUG + fprintf(stderr, "nxagentUniquePixels: pixels[%d][0x%08x].\n", + i, pixels[i]); + #endif + } + + break; + } + case 16: + case 15: + { + /* + * Note that the padding bytes at the end + * of the scanline are included in the set. + * This is not a big problem. What we want + * to find out is just how compressible is + * the image data. + */ + + for (i = 0; i < elements; i++) + { + pixels[i] = Get16(next, image -> byte_order); + + next += (2 * step); + + #ifdef DEBUG + fprintf(stderr, "nxagentUniquePixels: pixels[%d][0x%08x].\n", + i, pixels[i]); + #endif + } + + break; + } + default: + { + #ifdef PANIC + fprintf(stderr, "nxagentUniquePixels: PANIC! Assuming ratio [100] with [%d] bits per pixel.\n", + image -> bits_per_pixel); + #endif + + return 100; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentUniquePixels: Sorting [%d] elements in the list.\n", i); + #endif + + qsort(pixels, elements, sizeof(int), nxagentComparePixels); + + for (i = 0; i < elements; i++) + { + if (last != pixels[i]) + { + unique++; + + last = pixels[i]; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentUniquePixels: pixels[%d][0x%08x].\n", + i, pixels[i]); + #endif + } + + ratio = unique * 100 / elements; + + #ifdef TEST + fprintf(stderr, "nxagentUniquePixels: Found [%d] unique pixels out of [%d] with ratio [%d%%].\n", + unique, elements, ratio); + #endif + + return ratio; +} + +unsigned int Get16(const char *buffer, int order) +{ + unsigned int result; + + if (order == MSBFirst) + { + result = *buffer; + + result <<= 8; + + result += buffer[1]; + } + else + { + result = buffer[1]; + + result <<= 8; + + result += *buffer; + } + + return result; +} + +unsigned int Get24(const char *buffer, int order) +{ + int i; + + const char *next = (order == MSBFirst ? buffer : buffer + 2); + + unsigned int result = 0; + + for (i = 0; i < 3; i++) + { + result <<= 8; + + result += *next; + + if (order == MSBFirst) + { + next++; + } + else + { + next--; + } + } + + return result; +} + +unsigned int Get32(const char *buffer, int order) +{ + int i; + + const char *next = (order == MSBFirst ? buffer : buffer + 3); + + unsigned int result = 0; + + for (i = 0; i < 4; i++) + { + result <<= 8; + + result += *next; + + if (order == MSBFirst) + { + next++; + } + else + { + next--; + } + } + + return result; +} + +void Put16(unsigned int value, char *buffer, int order) +{ + if (order == MSBFirst) + { + buffer[1] = (unsigned char) (value & 0xff); + + value >>= 8; + + *buffer = (unsigned char) value; + } + else + { + *buffer = (unsigned char) (value & 0xff); + + value >>= 8; + + buffer[1] = (unsigned char) value; + } +} + +void Put24(unsigned int value, char *buffer, int order) +{ + int i; + + if (order == MSBFirst) + { + buffer += 2; + + for (i = 3; i > 0; i--) + { + *buffer-- = (unsigned char) (value & 0xff); + + value >>= 8; + } + } + else + { + for (i = 3; i > 0; i--) + { + *buffer++ = (unsigned char) (value & 0xff); + + value >>= 8; + } + } +} + +void Put32(unsigned int value, char *buffer, int order) +{ + int i; + + if (order == MSBFirst) + { + buffer += 3; + + for (i = 4; i > 0; i--) + { + *buffer-- = (unsigned char) (value & 0xff); + + value >>= 8; + } + } + else + { + for (i = 4; i > 0; i--) + { + *buffer++ = (unsigned char) (value & 0xff); + + value >>= 8; + } + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Pixels.h b/nx-X11/programs/Xserver/hw/nxagent/Pixels.h new file mode 100644 index 000000000..fa25a46c7 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Pixels.h @@ -0,0 +1,188 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Pixels_H__ +#define __Pixels_H__ + +#include "Visual.h" +#include "Drawable.h" +#include "Composite.h" + +/* + * Count how many pixels are different + * in the image. + */ + +int nxagentUniquePixels(XImage *image); + +/* + * Convert a 32 bit pixel to 16 bit. + */ + +#define Color32to16(color) \ +do \ +{ \ + Visual *pVisual; \ +\ + pVisual = nxagentDefaultVisual(nxagentDefaultScreen); \ +\ + if (pVisual -> green_mask == 0x7e0) \ + { \ + /* \ + * bit mask 5-6-5 \ + */ \ +\ + color = (((color & (pVisual -> blue_mask << 3)) >> 3) | \ + ((color & (pVisual -> green_mask << 5)) >> 5) | \ + ((color & (pVisual -> red_mask << 8)) >> 8)); \ + } \ + else \ + { \ + /* \ + * bit mask 5-5-5 \ + */ \ +\ + color = (((color & (pVisual -> blue_mask << 3)) >> 3) | \ + ((color & (pVisual -> green_mask << 6)) >> 6) | \ + ((color & (pVisual -> red_mask << 9)) >> 9)); \ + } \ +} \ +while (0) + +/* + * Rules to break the synchronization loop. + */ + +#define breakOnBlocking(mask) \ + (((mask) != NEVER_BREAK) && ((mask) & BLOCKING_BREAK) && \ + nxagentBlocking == 1) + +#define breakOnCongestion(mask) \ + (((mask) != NEVER_BREAK) && ((mask) & CONGESTION_BREAK) && \ + nxagentCongestion > 4) + +#define breakOnBlockingOrCongestion(mask) \ + (breakOnBlocking(mask) != 0 || breakOnCongestion(mask) != 0) + +#define breakOnCongestionDrawable(mask, pDrawable) \ + (((mask) != NEVER_BREAK) && ((mask) & CONGESTION_BREAK) && \ + (nxagentCongestion > 4 || \ + ((pDrawable) -> type == DRAWABLE_PIXMAP && \ + nxagentCongestion > 1))) + +#define breakOnEvent(mask) \ + (((mask) != NEVER_BREAK) && ((mask) & EVENT_BREAK) && \ + nxagentUserInput(NULL) == 1) + +#define canBreakOnTimeout(mask) \ + (((mask) != NEVER_BREAK) && nxagentOption(Shadow) == 0) + +/* + * Macros defining the conditions to + * defer X requests. + */ + +#define NXAGENT_SHOULD_DEFER_TRAPEZOIDS(pDrawable) \ + (nxagentOption(DeferLevel) >= 2 && \ + nxagentDrawableContainGlyphs(pDrawable) == 0 && \ + nxagentOption(LinkType) < LINK_TYPE_ADSL && \ + nxagentCongestion > 4) + +/* +FIXME: The condition checking for the render + version is a workaround implemented to + avoid problems with the render composi- + te on XFree86 remote server. +*/ +/* +FIXME: Changed macro: NXAGENT_SHOULD_DEFER_COMPOSITE + to handle situation, when pSrc -> pDrawable + is NULL. This case happens with gradients + and solid fill. + +#define NXAGENT_SHOULD_DEFER_COMPOSITE(pSrc, pMask, pDst) \ + ((nxagentRenderVersionMajor == 0 && \ + nxagentRenderVersionMinor == 8 && \ + (pDst) -> pDrawable -> type == DRAWABLE_PIXMAP) || \ + ((pDst) -> pDrawable -> type == DRAWABLE_PIXMAP && \ + (nxagentDrawableStatus((pSrc) -> pDrawable) == NotSynchronized || \ + ((pMask) && nxagentDrawableStatus((pMask) -> pDrawable) == NotSynchronized)) && \ + nxagentOption(DeferLevel) == 1) || \ + (nxagentOption(DeferLevel) >= 2 && \ + nxagentOption(LinkType) < LINK_TYPE_ADSL)) +*/ +#define NXAGENT_SHOULD_DEFER_COMPOSITE(pSrc, pMask, pDst) \ + ((nxagentRenderVersionMajor == 0 && \ + nxagentRenderVersionMinor == 8 && \ + (pDst) -> pDrawable -> type == DRAWABLE_PIXMAP) || \ + (nxagentOption(DeferLevel) >= 2 && \ + nxagentOption(LinkType) < LINK_TYPE_ADSL) || \ + (nxagentOption(DeferLevel) == 1 && \ + (pDst) -> pDrawable -> type == DRAWABLE_PIXMAP && \ + (((pSrc) -> pDrawable && nxagentDrawableStatus((pSrc) -> pDrawable) == NotSynchronized) || \ + ((pMask) && (pMask) -> pDrawable && nxagentDrawableStatus((pMask) -> pDrawable) == NotSynchronized)))) + + +#define NXAGENT_SHOULD_DEFER_PUTIMAGE(pDrawable) \ + (nxagentSplitTrap == 0 && \ + nxagentOption(DeferLevel) > 0) + +/* + * Macros defining the conditions to + * start the synchronization loops of + * resources. + */ + +#define NXAGENT_SHOULD_SYNCHRONIZE_CORRUPTED_WINDOWS(mask) \ + ((nxagentCorruptedWindows > 0 && breakOnBlockingOrCongestion(mask) == 0) || \ + mask == NEVER_BREAK) + +#define NXAGENT_SHOULD_SYNCHRONIZE_CORRUPTED_BACKGROUNDS(mask) \ + ((nxagentCorruptedWindows == 0 && nxagentCorruptedBackgrounds > 0 && \ + breakOnBlockingOrCongestion(mask) == 0) || mask == NEVER_BREAK) + +#define NXAGENT_SHOULD_SYNCHRONIZE_CORRUPTED_PIXMAPS(mask) \ + ((nxagentCorruptedWindows == 0 && nxagentCorruptedPixmaps > 0 && \ + nxagentCongestion == 0 && nxagentBlocking == 0) || \ + mask == NEVER_BREAK) + +/* + * Macros defining the conditions to + * synchronize a single resource. + */ + +#define NXAGENT_SHOULD_SYNCHRONIZE_WINDOW(pDrawable) \ + (nxagentWindowIsVisible((WindowPtr) pDrawable) == 1 && \ + (nxagentDefaultWindowIsVisible() == 1 || nxagentCompositeEnable == 1)) + +#define MINIMUM_PIXMAP_USAGE_COUNTER 2 + +#define NXAGENT_SHOULD_SYNCHRONIZE_PIXMAP(pDrawable) \ + (nxagentPixmapUsageCounter((PixmapPtr) pDrawable) >= \ + MINIMUM_PIXMAP_USAGE_COUNTER || \ + nxagentIsCorruptedBackground((PixmapPtr) pDrawable) == 1) + +#endif /* __Pixels_H__ */ + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Pixmap.c b/nx-X11/programs/Xserver/hw/nxagent/Pixmap.c new file mode 100644 index 000000000..be5408d13 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Pixmap.c @@ -0,0 +1,1660 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "scrnintstr.h" +#include "miscstruct.h" +#include "pixmapstr.h" +#include "dixstruct.h" +#include "regionstr.h" +#include "../../include/gc.h" +#include "servermd.h" +#include "mi.h" + +#include "../../fb/fb.h" + +#include "Agent.h" +#include "Display.h" +#include "Screen.h" +#include "Pixmaps.h" +#include "Trap.h" +#include "GCs.h" +#include "GCOps.h" +#include "Image.h" +#include "Split.h" +#include "Drawable.h" +#include "Visual.h" +#include "Client.h" +#include "Events.h" +#include "Holder.h" +#include "Args.h" + +#include "compext/Compext.h" +#include <nx/NXpack.h> + +RESTYPE RT_NX_PIXMAP; + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG +#undef DUMP + +#ifdef TEST +#include "Font.h" +#endif + +int nxagentPixmapPrivateIndex; + +int nxagentCorruptedPixmaps; +int nxagentCorruptedBackgrounds; + +/* + * Force deallocation of the virtual pixmap. + */ + +static Bool nxagentDestroyVirtualPixmap(PixmapPtr pPixmap); + +/* + * This serves as a tool to check the synchronization + * between pixmaps in framebuffer and the correspondent + * pixmaps in the real X server. + */ + +#ifdef TEST +Bool nxagentCheckPixmapIntegrity(PixmapPtr pPixmap); +#endif + +struct nxagentPixmapPair +{ + Pixmap pixmap; + PixmapPtr pMap; +}; + +PixmapPtr nxagentCreatePixmap(ScreenPtr pScreen, int width, int height, + int depth, unsigned usage_hint) +{ + nxagentPrivPixmapPtr pPixmapPriv, pVirtualPriv; + + PixmapPtr pPixmap; + PixmapPtr pVirtual; + + #ifdef DEBUG + fprintf(stderr, "nxagentCreatePixmap: Creating pixmap with width [%d] " + "height [%d] depth [%d] and allocation hint [%d].\n", + width, height, depth, usage_hint); + #endif + + /* + * Create the pixmap structure but do + * not allocate memory for the data. + */ + + pPixmap = AllocatePixmap(pScreen, 0); + + if (!pPixmap) + { + #ifdef WARNING + fprintf(stderr, "nxagentCreatePixmap: WARNING! Failed to create pixmap with " + "width [%d] height [%d] depth [%d] and allocation hint [%d].\n", + width, height, depth, usage_hint); + #endif + + return NullPixmap; + } + + /* + * Initialize the core members. + */ + + pPixmap -> drawable.type = DRAWABLE_PIXMAP; + pPixmap -> drawable.class = 0; + pPixmap -> drawable.pScreen = pScreen; + pPixmap -> drawable.depth = depth; + pPixmap -> drawable.bitsPerPixel = BitsPerPixel(depth); + pPixmap -> drawable.id = 0; + pPixmap -> drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap -> drawable.x = 0; + pPixmap -> drawable.y = 0; + pPixmap -> drawable.width = width; + pPixmap -> drawable.height = height; + pPixmap -> devKind = 0; + pPixmap -> refcnt = 1; + pPixmap -> devPrivate.ptr = NULL; + pPixmap -> usage_hint = usage_hint; + + /* + * Initialize the privates of the real picture. + */ + + pPixmapPriv = nxagentPixmapPriv(pPixmap); + + pPixmapPriv -> isVirtual = False; + pPixmapPriv -> isShared = nxagentShmPixmapTrap; + + /* + * The shared memory pixmaps are never + * synchronized with the remote X Server. + */ + + if (pPixmapPriv -> isShared == 1) + { + BoxRec box; + + box.x1 = 0; + box.y1 = 0; + box.x2 = width; + box.y2 = height; + + pPixmapPriv -> corruptedRegion = RegionCreate(&box, 1); + } + else + { + pPixmapPriv -> corruptedRegion = RegionCreate((BoxRec *) NULL, 1); + } + + pPixmapPriv -> corruptedBackground = 0; + + pPixmapPriv -> containGlyphs = 0; + pPixmapPriv -> containTrapezoids = 0; + + /* + * The lazy encoding policy generally does + * not send on remote X server the off-screen + * images, by preferring to synchronize the + * windows content. Anyway this behaviour may + * be inadvisable if a pixmap is used, for + * example, for multiple copy areas on screen. + * This counter serves the purpose, taking in- + * to account the number of times the pixmap + * has been used as source for a deferred + * operation. + */ + + pPixmapPriv -> usageCounter = 0; + + pPixmapPriv -> corruptedBackgroundId = 0; + pPixmapPriv -> corruptedId = 0; + + pPixmapPriv -> synchronizationBitmap = NullPixmap; + + pPixmapPriv -> corruptedTimestamp = 0; + + pPixmapPriv -> splitResource = NULL; + + pPixmapPriv -> isBackingPixmap = 0; + + /* + * Create the pixmap based on the default + * windows. The proxy knows this and uses + * this information to optimize encode the + * create pixmap message by including the + * id of the drawable in the checksum. + */ + + if (width != 0 && height != 0 && nxagentGCTrap == 0) + { + pPixmapPriv -> id = XCreatePixmap(nxagentDisplay, + nxagentDefaultWindows[pScreen -> myNum], + width, height, depth); + } + else + { + pPixmapPriv -> id = 0; + + #ifdef TEST + fprintf(stderr, "nxagentCreatePixmap: Skipping the creation of pixmap at [%p] on real " + "X server with nxagentGCTrap [%d].\n", (void *) pPixmap, nxagentGCTrap); + #endif + } + + pPixmapPriv -> mid = FakeClientID(serverClient -> index); + + AddResource(pPixmapPriv -> mid, RT_NX_PIXMAP, pPixmap); + + pPixmapPriv -> pRealPixmap = pPixmap; + pPixmapPriv -> pVirtualPixmap = NULL; + pPixmapPriv -> pPicture = NULL; + + /* + * Create the pixmap in the virtual framebuffer. + */ + + pVirtual = fbCreatePixmap(pScreen, width, height, depth, usage_hint); + + if (pVirtual == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentCreatePixmap: PANIC! Failed to create virtual pixmap with " + "width [%d] height [%d] depth [%d] and allocation hint [%d].\n", + width, height, depth, usage_hint); + #endif + + nxagentDestroyPixmap(pPixmap); + + return NullPixmap; + } + + #ifdef TEST + fprintf(stderr,"nxagentCreatePixmap: Allocated memory for the Virtual %sPixmap %p of real Pixmap %p (%dx%d),", + "allocation hint [%d].\n", + nxagentShmPixmapTrap ? "Shm " : "", (void *) pVirtual, (void *) pPixmap, width, height, usage_hint); + #endif + + pPixmapPriv -> pVirtualPixmap = pVirtual; + + /* + * Initialize the privates of the virtual picture. We + * could avoid to use a flag and just check the pointer + * to the virtual pixmap that, if the pixmap is actually + * virtual, will be NULL. Unfortunately the flag can be + * changed in nxagentValidateGC(). That code should be + * removed in future. + */ + + pVirtualPriv = nxagentPixmapPriv(pVirtual); + + pVirtualPriv -> isVirtual = True; + pVirtualPriv -> isShared = nxagentShmPixmapTrap; + + pVirtualPriv -> corruptedRegion = RegionCreate((BoxRec *) NULL, 1); + + pVirtualPriv -> corruptedBackground = 0; + + pVirtualPriv -> containGlyphs = 0; + pVirtualPriv -> containTrapezoids = 0; + + pVirtualPriv -> usageCounter = 0; + + pVirtualPriv -> corruptedBackgroundId = 0; + pVirtualPriv -> corruptedId = 0; + + pVirtualPriv -> synchronizationBitmap = NullPixmap; + + pVirtualPriv -> corruptedTimestamp = 0; + + pVirtualPriv -> splitResource = NULL; + + /* + * We might distinguish real and virtual pixmaps by + * checking the pointers to pVirtualPixmap. We should + * also remove the copy of id and use the one of the + * real pixmap. + */ + + pVirtualPriv -> id = pPixmapPriv -> id; + pVirtualPriv -> mid = 0; + + /* + * Storing a pointer back to the real pixmap is + * silly. Unfortunately this is the way it has + * been originally implemented. See also the + * comment in destroy of the pixmap. + */ + + pVirtualPriv -> pRealPixmap = pPixmap; + pVirtualPriv -> pVirtualPixmap = NULL; + pVirtualPriv -> pPicture = NULL; + + /* + * Check that the virtual pixmap is created with + * the appropriate bits-per-plane, otherwise free + * everything and return. + */ + + if (pVirtual -> drawable.bitsPerPixel == 0) + { + #ifdef WARNING + + fprintf(stderr, "nxagentCreatePixmap: WARNING! Virtual pixmap at [%p] has invalid " + "bits per pixel.\n", (void *) pVirtual); + + fprintf(stderr, "nxagentCreatePixmap: WARNING! Real pixmap created with width [%d] " + "height [%d] depth [%d] bits per pixel [%d] and allocation hint [%d].\n", + pPixmap -> drawable.width, + pPixmap -> drawable.height = height, pPixmap -> drawable.depth, + pPixmap -> drawable.bitsPerPixel, + usage_hint); + #endif + + if (!nxagentRenderTrap) + { + #ifdef WARNING + fprintf(stderr, "Warning: Disabling render extension due to missing pixmap format.\n"); + #endif + + nxagentRenderTrap = 1; + } + + nxagentDestroyPixmap(pPixmap); + + return NullPixmap; + } + + #ifdef TEST + fprintf(stderr, "nxagentCreatePixmap: Created pixmap at [%p] virtual at [%p] with width [%d] " + "height [%d] depth [%d] and allocation hint [%d].\n", + (void *) pPixmap, (void *) pVirtual, width, height, depth, usage_hint); + #endif + + return pPixmap; +} + +Bool nxagentDestroyPixmap(PixmapPtr pPixmap) +{ + PixmapPtr pVirtual; + + nxagentPrivPixmapPtr pPixmapPriv; + + if (!pPixmap) + { + #ifdef PANIC + fprintf(stderr, "nxagentDestroyPixmap: PANIC! Invalid attempt to destroy " + "a null pixmap pointer.\n"); + #endif + + return False; + } + + pPixmapPriv = nxagentPixmapPriv(pPixmap); + + pVirtual = pPixmapPriv -> pVirtualPixmap; + + #ifdef TEST + fprintf(stderr, "nxagentDestroyPixmap: Destroying pixmap at [%p] with virtual at [%p].\n", + (void *) pPixmap, (void *) pVirtual); + #endif + + if (pPixmapPriv -> isVirtual) + { + int refcnt; + + /* + * For some pixmaps we receive the destroy only for the + * virtual. Infact to draw in the framebuffer we can use + * the virtual pixmap instead of the pointer to the real + * one. As the virtual pixmap can collect references, we + * must transfer those references to the real pixmap so + * we can continue as the destroy had been requested for + * it. + */ + + pVirtual = pPixmap; + pPixmap = pPixmapPriv -> pRealPixmap; + + pPixmapPriv = nxagentPixmapPriv(pPixmap); + + /* + * Move the references accumulated by the virtual + * pixmap into the references of the real one. + */ + + refcnt = pVirtual -> refcnt - 1; + + #ifdef TEST + fprintf(stderr, "nxagentDestroyPixmap: Adding [%d] references to pixmap at [%p].\n", + refcnt, (void *) pPixmap); + #endif + + pPixmap -> refcnt += refcnt; + + pVirtual -> refcnt -= refcnt; + } + + --pPixmap -> refcnt; + + #ifdef TEST + + fprintf(stderr, "nxagentDestroyPixmap: Pixmap has now [%d] references with virtual pixmap [%d].\n", + pPixmap -> refcnt, pVirtual -> refcnt); + + if (pVirtual != NULL && pVirtual -> refcnt != 1) + { + fprintf(stderr, "nxagentDestroyPixmap: PANIC! Virtual pixmap has [%d] references.\n", + pVirtual -> refcnt); + } + + #endif + + if (pPixmap -> refcnt > 0) + { + return True; + } + + #ifdef TEST + + fprintf(stderr, "nxagentDestroyPixmap: Managing to destroy the pixmap at [%p]\n", + (void *) pPixmap); + #endif + + nxagentRemoveItemBSPixmapList(nxagentPixmap(pPixmap)); + + nxagentDestroyVirtualPixmap(pPixmap); + + if (pPixmapPriv -> corruptedRegion != NullRegion) + { + RegionDestroy(pPixmapPriv -> corruptedRegion); + + pPixmapPriv -> corruptedRegion = NullRegion; + } + + if (nxagentSynchronization.pDrawable == (DrawablePtr) pPixmap) + { + nxagentSynchronization.pDrawable = NULL; + + #ifdef TEST + fprintf(stderr, "nxagentDestroyPixmap: Synchronization drawable [%p] removed from resources.\n", + (void *) pPixmap); + #endif + } + + nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_BACKGROUND); + + nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP); + + nxagentDestroyDrawableBitmap((DrawablePtr) pPixmap); + + if (pPixmapPriv -> splitResource != NULL) + { + nxagentReleaseSplit((DrawablePtr) pPixmap); + } + + /* + * A pixmap with width and height set to 0 is + * created at the beginning. To this pixmap is + * not assigned an id. This is likely a scratch + * pixmap used by the X server. + */ + + if (pPixmapPriv -> id) + { + XFreePixmap(nxagentDisplay, pPixmapPriv -> id); + } + + if (pPixmapPriv -> mid) + { + FreeResource(pPixmapPriv -> mid, RT_NONE); + } + + free(pPixmap); + + return True; +} + +Bool nxagentDestroyVirtualPixmap(PixmapPtr pPixmap) +{ + PixmapPtr pVirtual; + nxagentPrivPixmapPtr pVirtualPriv; + + pVirtual = nxagentPixmapPriv(pPixmap) -> pVirtualPixmap; + + /* + * Force the routine to get rid of the virtual + * pixmap. + */ + + if (pVirtual != NULL) + { + pVirtual -> refcnt = 1; + + pVirtualPriv = nxagentPixmapPriv(pVirtual); + + if (pVirtualPriv -> corruptedRegion != NullRegion) + { + RegionDestroy(pVirtualPriv -> corruptedRegion); + + pVirtualPriv -> corruptedRegion = NullRegion; + } + + fbDestroyPixmap(pVirtual); + } + + return True; +} + +RegionPtr nxagentPixmapToRegion(PixmapPtr pPixmap) +{ + #ifdef TEST + fprintf(stderr, "PixmapToRegion: Pixmap = [%p] nxagentVirtualPixmap = [%p]\n", + (void *) pPixmap, (void *) nxagentVirtualPixmap(pPixmap)); + #endif + + return fbPixmapToRegion(nxagentVirtualPixmap(pPixmap)); +} + +Bool nxagentModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, void * pPixData) +{ + PixmapPtr pVirtualPixmap; + + /* + * See miModifyPixmapHeader() in miscrinit.c. This + * function is used to recycle the scratch pixmap + * for this screen. We let it refer to the virtual + * pixmap. + */ + + if (!pPixmap) + { + return False; + } + + if (nxagentPixmapIsVirtual(pPixmap)) + { + #ifdef PANIC + fprintf(stderr, "nxagentModifyPixmapHeader: PANIC! Pixmap at [%p] is virtual.\n", + (void *) pPixmap); + #endif + + FatalError("nxagentModifyPixmapHeader: PANIC! Pixmap is virtual."); + } + + pVirtualPixmap = nxagentVirtualPixmap(pPixmap); + + #ifdef TEST + fprintf(stderr, "nxagentModifyPixmapHeader: Pixmap at [%p] Virtual at [%p].\n", + (void *) pPixmap, (void *) pVirtualPixmap); + + fprintf(stderr, "nxagentModifyPixmapHeader: Pixmap has width [%d] height [%d] depth [%d] " + "bits-per-pixel [%d] devKind [%d] pPixData [%p].\n", pPixmap->drawable.width, + pPixmap->drawable.height, pPixmap->drawable.depth, pPixmap->drawable.bitsPerPixel, + pPixmap->devKind, (void *) pPixmap->devPrivate.ptr); + + fprintf(stderr, "nxagentModifyPixmapHeader: New parameters are width [%d] height [%d] depth [%d] " + "bits-per-pixel [%d] devKind [%d] pPixData [%p].\n", width, height, depth, + bitsPerPixel, devKind, (void *) pPixData); + #endif + + if ((width > 0) && (height > 0) && (depth > 0) && + (bitsPerPixel > 0) && (devKind > 0) && pPixData) + { + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bitsPerPixel; + pPixmap->drawable.id = 0; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = devKind; + pPixmap->refcnt = 1; + pPixmap->devPrivate.ptr = pPixData; + + pVirtualPixmap->drawable.depth = depth; + pVirtualPixmap->drawable.bitsPerPixel = bitsPerPixel; + pVirtualPixmap->drawable.id = 0; + pVirtualPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pVirtualPixmap->drawable.x = 0; + pVirtualPixmap->drawable.y = 0; + pVirtualPixmap->drawable.width = width; + pVirtualPixmap->drawable.height = height; + pVirtualPixmap->devKind = devKind; + pVirtualPixmap->refcnt = 1; + pVirtualPixmap->devPrivate.ptr = pPixData; + } + else + { + if (width > 0) + pPixmap->drawable.width = width; + + if (height > 0) + pPixmap->drawable.height = height; + + if (depth > 0) + pPixmap->drawable.depth = depth; + + if (bitsPerPixel > 0) + pPixmap->drawable.bitsPerPixel = bitsPerPixel; + else if ((bitsPerPixel < 0) && (depth > 0)) + pPixmap->drawable.bitsPerPixel = BitsPerPixel(depth); + + if (devKind > 0) + pPixmap->devKind = devKind; + else if ((devKind < 0) && ((width > 0) || (depth > 0))) + pPixmap->devKind = PixmapBytePad(pPixmap->drawable.width, + pPixmap->drawable.depth); + + if (pPixData) + pPixmap->devPrivate.ptr = pPixData; + + /* + * XXX This was the previous assignment: + * + * pVirtualPixmap->devPrivate.ptr = pPixData; + */ + + if (width > 0) + pVirtualPixmap->drawable.width = width; + + if (height > 0) + pVirtualPixmap->drawable.height = height; + + if (depth > 0) + pVirtualPixmap->drawable.depth = depth; + + if (bitsPerPixel > 0) + pVirtualPixmap->drawable.bitsPerPixel = bitsPerPixel; + else if ((bitsPerPixel < 0) && (depth > 0)) + pVirtualPixmap->drawable.bitsPerPixel = BitsPerPixel(depth); + + if (devKind > 0) + pVirtualPixmap->devKind = devKind; + else if ((devKind < 0) && ((width > 0) || (depth > 0))) + pVirtualPixmap->devKind = PixmapBytePad(pVirtualPixmap->drawable.width, + pVirtualPixmap->drawable.depth); + + if (pPixData) + pVirtualPixmap->devPrivate.ptr = pPixData; + + #ifdef PANIC + + if (pPixmap->drawable.x != 0 || pPixmap->drawable.y != 0) + { + fprintf(stderr, "nxagentModifyPixmapHeader: PANIC! Pixmap at [%p] has x [%d] and y [%d].\n", + (void *) pPixmap, pPixmap->drawable.x, pPixmap->drawable.y); + + FatalError("nxagentModifyPixmapHeader: PANIC! Pixmap has x or y greater than zero."); + } + + #endif + } + + return True; +} + +static void nxagentPixmapMatchID(void *p0, XID x1, void *p2) +{ + PixmapPtr pPixmap = (PixmapPtr)p0; + struct nxagentPixmapPair *pPair = p2; + + if ((pPair -> pMap == NULL) && (nxagentPixmap(pPixmap) == pPair -> pixmap)) + { + pPair -> pMap = pPixmap; + } +} + +PixmapPtr nxagentPixmapPtr(Pixmap pixmap) +{ + int i; + struct nxagentPixmapPair pair; + + if (pixmap == None) + { + return NULL; + } + + pair.pixmap = pixmap; + pair.pMap = NULL; + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, + nxagentPixmapMatchID, &pair); + + for (i = 0; (pair.pMap == NULL) && (i < MAXCLIENTS); i++) + { + if (clients[i]) + { + FindClientResourcesByType(clients[i], RT_PIXMAP, + nxagentPixmapMatchID, &pair); + } + } + + #ifdef WARNING + + if (pair.pMap == NULL) + { + fprintf(stderr, "nxagentFindPixmap: WARNING! Failed to find " + "remote pixmap [%ld].\n", (long int) pair.pixmap); + } + else if (nxagentDrawableStatus((DrawablePtr) pair.pMap) == NotSynchronized) + { + fprintf(stderr, "WARNING! Rootless icon at [%p] [%d,%d] is not synchronized.\n", + (void *) pair.pMap, pair.pMap -> drawable.width, + pair.pMap -> drawable.height); + } + + #endif + + return pair.pMap; +} + +/* + * Reconnection stuff. + */ + +int nxagentDestroyNewPixmapResourceType(void * p, XID id) +{ + /* + * Address of the destructor is set in Init.c. + */ + + #ifdef TEST + fprintf(stderr, "nxagentDestroyNewPixmapResourceType: Destroying mirror id [%ld] for pixmap at [%p].\n", + nxagentPixmapPriv((PixmapPtr) p) -> mid, (void *) p); + #endif + + nxagentPixmapPriv((PixmapPtr) p) -> mid = None; + + return True; +} + +void nxagentDisconnectPixmap(void *p0, XID x1, void *p2) +{ + PixmapPtr pPixmap = (PixmapPtr) p0; + + #ifdef TEST + Bool *pBool; + + pBool = (Bool*) p2; + + fprintf(stderr, "nxagentDisconnectPixmap: Called with bool [%d] and pixmap at [%p].\n", + *pBool, (void *) pPixmap); + + fprintf(stderr, "nxagentDisconnectPixmap: Virtual pixmap is [%ld].\n", + nxagentPixmap(pPixmap)); + #endif + + nxagentPixmap(pPixmap) = None; + + if (nxagentDrawableStatus((DrawablePtr) pPixmap) == NotSynchronized) + { + nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_BACKGROUND); + + nxagentDestroyCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP); + } +} + +Bool nxagentDisconnectAllPixmaps() +{ + int r = 1; + int i; + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectAllPixmaps: Going to iterate through pixmap resources.\n"); + #endif + + /* + * The RT_NX_PIXMAP resource type is allocated + * only on the server client, so we don't need + * to find it through the other clients too. + */ + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, nxagentDisconnectPixmap, &r); + + #ifdef WARNING + + if (r == 0) + { + fprintf(stderr, "nxagentDisconnectAllPixmaps: WARNING! Failed to disconnect " + "pixmap for client [%d].\n", serverClient -> index); + } + + #endif + + for (i = 0, r = 1; i < MAXCLIENTS; r = 1, i++) + { + if (clients[i]) + { + #ifdef TEST + fprintf(stderr, "nxagentDisconnectAllPixmaps: Going to disconnect pixmaps of client [%d].\n", i); + #endif + + FindClientResourcesByType(clients[i], RT_PIXMAP, nxagentDisconnectPixmap, &r); + + #ifdef WARNING + + if (r == 0) + { + fprintf(stderr, "nxagentDisconnectAllPixmaps: WARNING! Failed to disconnect " + "pixmap for client [%d].\n", i); + } + + #endif + } + } + + #ifdef WARNING + + if (r == 0) + { + fprintf(stderr, "nxagentDisconnectAllPixmaps: WARNING! Failed to disconnect " + "pixmap for client [%d].\n", i); + } + + #endif + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectAllPixmaps: Pixmaps disconnection completed.\n"); + #endif + + return r; +} + +void nxagentReconnectPixmap(void *p0, XID x1, void *p2) +{ + PixmapPtr pPixmap = (PixmapPtr) p0; + Bool *pBool = (Bool*) p2; + nxagentPrivPixmapPtr pPixmapPriv; + + if (*pBool == 0 || pPixmap == NULL || + NXDisplayError(nxagentDisplay) == 1) + { + *pBool = 0; + + #ifdef TEST + fprintf(stderr, "nxagentReconnectPixmap: Ignoring pixmap at [%p] while " + "recovering from the error.\n", (void *) pPixmap); + #endif + + return; + } + else if (pPixmap == nxagentDefaultScreen -> pScratchPixmap) + { + /* + * Every time the scratch pixmap is used its + * data is changed, so we don't need to recon- + * nect it. + */ + + #ifdef TEST + fprintf(stderr, "nxagentReconnectPixmap: Ignoring scratch pixmap at [%p].\n", + (void *) pPixmap); + #endif + + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentReconnectPixmap: Called with result [%d] and pixmap at [%p].\n", + *pBool, (void *) pPixmap); + + fprintf(stderr, "nxagentReconnectPixmap: Virtual pixmap is at [%p] picture is at [%p].\n", + (void *) nxagentPixmapPriv(pPixmap) -> pVirtualPixmap, + (void *) nxagentPixmapPriv(pPixmap) -> pPicture); + #endif + + pPixmapPriv = nxagentPixmapPriv(pPixmap); + + if (pPixmap -> drawable.width && pPixmap -> drawable.height) + { + pPixmapPriv -> id = XCreatePixmap(nxagentDisplay, + nxagentDefaultWindows[pPixmap -> drawable.pScreen -> myNum], + pPixmap -> drawable.width, + pPixmap -> drawable.height, + pPixmap -> drawable.depth); + + nxagentPixmap(pPixmapPriv -> pVirtualPixmap) = pPixmapPriv -> id; + + #ifdef TEST + fprintf(stderr, "nxagentReconnectPixmap: Created virtual pixmap with id [%ld] for pixmap at [%p].\n", + nxagentPixmap(pPixmap), (void *) pPixmap); + #endif + + if (pPixmap == (PixmapPtr) nxagentDefaultScreen -> devPrivate) + { + #ifdef WARNING + fprintf(stderr, "nxagentReconnectPixmap: WARNING! Pixmap is root screen. Returning.\n"); + #endif + + return; + } + + nxagentSplitTrap = 1; + + *pBool = nxagentSynchronizeDrawableData((DrawablePtr) pPixmap, NEVER_BREAK, NULL); + + nxagentSplitTrap = 0; + + if (*pBool == 0) + { + #ifdef PANIC + fprintf(stderr, "nxagentReconnectPixmap: PANIC! Failed to synchronize the pixmap.\n"); + #endif + } + + + if (nxagentDrawableStatus((DrawablePtr) pPixmap) == NotSynchronized) + { + if (nxagentIsCorruptedBackground(pPixmap) == 1) + { + nxagentAllocateCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_BACKGROUND); + + nxagentFillRemoteRegion((DrawablePtr) pPixmap, + nxagentCorruptedRegion((DrawablePtr) pPixmap)); + } + else + { + nxagentAllocateCorruptedResource((DrawablePtr) pPixmap, RT_NX_CORR_PIXMAP); + } + } + } +} + +Bool nxagentReconnectAllPixmaps(void *p0) +{ + Bool result = 1; + + int i; + + #ifdef TEST + fprintf(stderr, "nxagentReconnectAllPixmaps: Going to recreate all pixmaps.\n"); + #endif + + /* + * Reset the geometry and alpha information + * used by proxy to unpack the packed images. + */ + + nxagentResetVisualCache(); + + nxagentResetAlphaCache(); + + /* + * The RT_NX_PIXMAP resource type is allocated + * only on the server client, so we don't need + * to find it through the other clients too. + */ + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, nxagentReconnectPixmap, &result); + + #ifdef WARNING + + if (result == 0) + { + fprintf(stderr, "nxagentReconnectAllPixmaps: WARNING! Failed to reconnect " + "pixmap for client [%d].\n", serverClient -> index); + } + + #endif + + for (i = 0, result = 1; i < MAXCLIENTS; result = 1, i++) + { + if (clients[i] != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentReconnectAllPixmaps: Going to reconnect pixmaps of client [%d].\n", i); + #endif + + /* + * Let the pixmap be reconnected as it was an + * image request issued by the client owning + * the resource. The client index is used as + * a subscript by the image routines to cache + * the data per-client. + */ + + FindClientResourcesByType(clients[i], RT_PIXMAP, nxagentReconnectPixmap, &result); + + #ifdef WARNING + + if (result == 0) + { + fprintf(stderr, "nxagentReconnectAllPixmaps: WARNING! Failed to reconnect " + "pixmap for client [%d].\n", serverClient -> index); + } + + #endif + } + } + + #ifdef TEST + fprintf(stderr, "nxagentReconnectAllPixmaps: Pixmaps reconnection completed.\n"); + #endif + + return result; +} + +#ifdef TEST + +static void nxagentCheckOnePixmapIntegrity(void *p0, XID x1, void *p2) +{ + PixmapPtr pPixmap = (PixmapPtr) p0; + Bool *pBool = (Bool*) p2; + + if (*pBool == False) + { + return; + } + + if (pPixmap == nxagentDefaultScreen -> devPrivate) + { + #ifdef TEST + fprintf(stderr, "nxagentCheckOnePixmapIntegrity: pixmap %p is screen.\n", + (void *) pPixmap); + #endif + + return; + } + + if (pPixmap == nxagentDefaultScreen -> PixmapPerDepth[0]) + { + #ifdef TEST + fprintf(stderr, "nxagentCheckOnePixmapIntegrity: pixmap %p is default stipple of screen.\n", + (void *) pPixmap); + #endif + + return; + } + + *pBool = nxagentCheckPixmapIntegrity(pPixmap); +} + +Bool nxagentCheckPixmapIntegrity(PixmapPtr pPixmap) +{ + Bool integrity = 1; + XImage *image; + char *data; + int format; + unsigned long plane_mask = AllPlanes; + unsigned int width, height, length, depth; + PixmapPtr pVirtual = nxagentVirtualPixmap(pPixmap); + + width = pPixmap -> drawable.width; + height = pPixmap -> drawable.height; + depth = pPixmap -> drawable.depth; + format = (depth == 1) ? XYPixmap : ZPixmap; + + if (width && height) + { + length = nxagentImageLength(width, height, format, 0, depth); + + data = malloc(length); + + if (data == NULL) + { + FatalError("nxagentCheckPixmapIntegrity: Failed to allocate a buffer of size %d.\n", length); + } + + image = XGetImage(nxagentDisplay, nxagentPixmap(pPixmap), 0, 0, + width, height, plane_mask, format); + if (image == NULL) + { + FatalError("XGetImage: Failed.\n"); + + free(data); + + return False; + } + + #ifdef WARNING + fprintf(stderr, "nxagentCheckPixmapIntegrity: Image from X has length [%d] and checksum [0x%s].\n", + length, nxagentChecksum(image->data, length)); + #endif + + NXCleanImage(image); + + #ifdef WARNING + fprintf(stderr, "nxagentCheckPixmapIntegrity: Image after clean has checksum [0x%s].\n", + nxagentChecksum(image->data, length)); + #endif + + fbGetImage((DrawablePtr) pVirtual, 0, 0, width, height, format, plane_mask, data); + + #ifdef WARNING + fprintf(stderr, "nxagentCheckPixmapIntegrity: Image from FB has length [%d] and checksum [0x%s].\n", + length, nxagentChecksum(data, length)); + #endif + + if (image != NULL && memcmp(image -> data, data, length) != 0) + { + integrity = 0; + } + else + { + integrity = 1; + + #ifdef TEST + fprintf(stderr, "nxagentCheckPixmapIntegrity: Pixmap at [%p] has been realized. " + "Now remote and frambuffer data are synchronized.\n", (void *) pPixmap); + #endif + } + + #ifdef WARNING + + if (integrity == 0) + { + + int i; + char *p, *q; + + for (i = 0, p = image -> data, q = data; i < length; i++) + { + if (p[i] != q[i]) + { + fprintf(stderr, "nxagentCheckPixmapIntegrity: Byte [%d] image -> data [%d] data [%d]. " + "Buffers differ!\n", i, p[i], q[i]); + } + else + { + fprintf(stderr, "nxagentCheckPixmapIntegrity: Byte [%d] image -> data [%d] data [%d].\n", + i, p[i], q[i]); + } + } + + fprintf(stderr, "nxagentCheckPixmapIntegrity: Pixmap at [%p] width [%d], height [%d], has been realized " + "but the data buffer still differs.\n", (void *) pPixmap, width, height); + + fprintf(stderr, "nxagentCheckPixmapIntegrity: bytes_per_line [%d] byte pad [%d] format [%d].\n", + image -> bytes_per_line, nxagentImagePad(width, height, 0, depth), image -> format); + + FatalError("nxagentCheckPixmapIntegrity: Image is corrupted!!\n"); + + } + + #endif + + if (image != NULL) + { + XDestroyImage(image); + } + + if (data != NULL) + { + free(data); + } + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckPixmapIntegrity: Ignored pixmap at [%p] with geometry [%d] [%d].\n", + (void *) pPixmap, width, height); + #endif + } + + return integrity; +} + +Bool nxagentCheckAllPixmapIntegrity() +{ + int i; + Bool imageIsGood = True; + + #ifdef TEST + fprintf(stderr, "nxagentCheckAllPixmapIntegrity\n"); + #endif + + FindClientResourcesByType(clients[serverClient -> index], RT_NX_PIXMAP, + nxagentCheckOnePixmapIntegrity, &imageIsGood); + + for (i = 0; (i < MAXCLIENTS) && (imageIsGood); i++) + { + if (clients[i]) + { + FindClientResourcesByType(clients[i], RT_PIXMAP, + nxagentCheckOnePixmapIntegrity, &imageIsGood); + + } + } + + #ifdef TEST + fprintf(stderr, "nxagentCheckAllPixmapIntegrity: pixmaps integrity = %d.\n", imageIsGood); + #endif + + return imageIsGood; +} + +#endif + +void nxagentSynchronizeShmPixmap(DrawablePtr pDrawable, int xPict, int yPict, + int wPict, int hPict) +{ + GCPtr pGC; + char *data; + int width, height; + int depth, length, format; + CARD32 attributes[3]; + + int saveTrap; + + if (pDrawable -> type == DRAWABLE_PIXMAP && + nxagentIsShmPixmap((PixmapPtr) pDrawable) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentSynchronizeShmPixmap: WARNING! Synchronizing shared pixmap at [%p].\n", + (void *) pDrawable); + #endif + + pGC = nxagentGetScratchGC(pDrawable -> depth, pDrawable -> pScreen); + + attributes[0] = 0x228b22; + attributes[1] = 0xffffff; + attributes[2] = FillSolid; + + ChangeGC(pGC, GCForeground | GCBackground | GCFillStyle, attributes); + + ValidateGC(pDrawable, pGC); + + width = (wPict != 0 && wPict <= pDrawable -> width) ? wPict : pDrawable -> width; + height = (hPict != 0 && hPict <= pDrawable -> height) ? hPict : pDrawable -> height; + + depth = pDrawable -> depth; + + format = (depth == 1) ? XYPixmap : ZPixmap; + + length = nxagentImageLength(width, height, format, 0, depth); + + saveTrap = nxagentGCTrap; + + nxagentGCTrap = 0; + + nxagentSplitTrap = 1; + + nxagentFBTrap = 1; + + if ((data = malloc(length)) != NULL) + { + fbGetImage(nxagentVirtualDrawable(pDrawable), xPict, yPict, + width, height, format, 0xffffffff, data); + + nxagentPutImage(pDrawable, pGC, depth, xPict, yPict, + width, height, 0, format, data); + + free(data); + } + #ifdef WARNING + else + { + fprintf(stderr, "nxagentSynchronizeShmPixmap: WARNING! Failed to allocate memory for the operation.\n"); + } + #endif + + nxagentGCTrap = saveTrap; + + nxagentSplitTrap = 0; + + nxagentFBTrap = 0; + + nxagentFreeScratchGC(pGC); + } +} + +#ifdef DUMP + +/* + * This function is useful to visualize a pixmap and check + * its data consistency. To avoid the creation of many + * windows, one pixmap only can be monitored at a time. + */ + +Bool nxagentPixmapOnShadowDisplay(PixmapPtr pMap) +{ + static Display *shadow; + static Window win; + static int init = True; + static int showTime; + static PixmapPtr pPixmap; + static int depth; + static int width; + static int height; + static int length; + static unsigned int format; + + XlibGC gc; + XGCValues value; + XImage *image; + Visual *pVisual; + char *data = NULL; + + + if (init) + { + if (pMap == NULL) + { + return False; + } + else + { + pPixmap = pMap; + } + + depth = pPixmap -> drawable.depth; + width = pPixmap -> drawable.width; + height = pPixmap -> drawable.height; + format = (depth == 1) ? XYPixmap : ZPixmap; + + shadow = XOpenDisplay("localhost:0"); + + if (shadow == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentPixmapOnShadowDisplay: WARNING! Shadow display not opened.\n"); + #endif + + return False; + } + + init = False; + + win = XCreateSimpleWindow(shadow, DefaultRootWindow(shadow), 0, 0, + width, height, 0, 0xFFCC33, 0xFF); + + XMapWindow(shadow, win); + XClearWindow(shadow, win); + } + +/* +FIXME: If the pixmap has a different depth from the window, the + XPutImage returns a BadMatch. For example this may happens if + the Render extension is enabled. + Can we fix this creating a new pixmap? +*/ + + if (DisplayPlanes(shadow, DefaultScreen(shadow)) != depth) + { + #ifdef WARNING + fprintf(stderr, "nxagentPixmapOnShadowDisplay: Pixmap and Window depths [%d - %d] are not equals!\n", + depth, DisplayPlanes(shadow, DefaultScreen(shadow))); + #endif + + return False; + } + + /* + * If the framebuffer is updated continuously, the nxagent + * visualization become too much slow. + */ + + if ((GetTimeInMillis() - showTime) < 500) + { + return False; + } + + showTime = GetTimeInMillis(); + + length = nxagentImageLength(width, height, format, 0, depth); + + if ((data = malloc(length)) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentPixmapOnShadowDisplay: WARNING! Failed to allocate memory for the operation.\n"); + #endif + + return False; + } + + fbGetImage((DrawablePtr) nxagentVirtualPixmap(pPixmap), 0, 0, + width, height, format, AllPlanes, data); + + pVisual = nxagentImageVisual((DrawablePtr) pPixmap, depth); + + if (pVisual == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentPixmapOnShadowDisplay: WARNING! Visual not found. Using default visual.\n"); + #endif + + pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual; + } + + image = XCreateImage(nxagentDisplay, pVisual, + depth, format, 0, (char *) data, + width, height, BitmapPad(nxagentDisplay), + nxagentImagePad(width, format, 0, depth)); + + if (image == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentPixmapOnShadowDisplay: XCreateImage failed.\n"); + #endif + + if (data != NULL) + { + free(data); + } + + return False; + } + + value.foreground = 0xff0000; + value.background = 0x000000; + value.plane_mask = 0xffffff; + value.fill_style = FillSolid; + + gc = XCreateGC(shadow, win, GCBackground | + GCForeground | GCFillStyle | GCPlaneMask, &value); + + NXCleanImage(image); + + XPutImage(shadow, win, gc, image, 0, 0, 0, 0, width, height); + + XFreeGC(shadow, gc); + + if (image != NULL) + { + XDestroyImage(image); + } + + return True; +} + +Bool nxagentFbOnShadowDisplay() +{ + static Display *shadow; + static Window win; + static int init = True; + static int showTime; + static int prevWidth, prevHeight; + + XlibGC gc; + XGCValues value; + XImage *image; + Visual *pVisual; + WindowPtr pWin = screenInfo.screens[0]->root; + unsigned int format; + int depth, width, height, length; + char *data = NULL; + + + if (pWin == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentFbOnShadowDisplay: The parent window is NULL.\n"); + #endif + + return False; + } + + depth = pWin -> drawable.depth; + width = pWin -> drawable.width; + height = pWin -> drawable.height; + format = (depth == 1) ? XYPixmap : ZPixmap; + + if (init) + { + shadow = XOpenDisplay("localhost:0"); + + if (shadow == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentFbOnShadowDisplay: WARNING! Shadow display not opened.\n"); + #endif + + return False; + } + + init = False; + + prevWidth = width; + prevHeight = height; + + win = XCreateSimpleWindow(shadow, DefaultRootWindow(shadow), 0, 0, + width, height, 0, 0xFFCC33, 0xFF); + + XMapWindow(shadow, win); + XClearWindow(shadow, win); + } + + if (DisplayPlanes(shadow, DefaultScreen(shadow)) != depth) + { + #ifdef WARNING + fprintf(stderr, "nxagentFbOnShadowDisplay: Depths [%d - %d] are not equals!\n", + depth, DisplayPlanes(shadow, DefaultScreen(shadow))); + #endif + + return False; + } + + /* + * If the framebuffer is updated continuously, the nxagent + * visualization becomes too much slow. + */ + + if ((GetTimeInMillis() - showTime) < 500) + { + return False; + } + + showTime = GetTimeInMillis(); + + /* + * If the root window is resized, also the window on shadow + * display must be resized. + */ + + if (prevWidth != width || prevHeight != height) + { + XWindowChanges values; + + prevWidth = width; + prevHeight = height; + + values.width = width; + values.height = height; + XConfigureWindow(shadow, win, CWWidth | CWHeight, &values); + } + + length = nxagentImageLength(width, height, format, 0, depth); + + if ((data = malloc(length)) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentFbOnShadowDisplay: WARNING! Failed to allocate memory for the operation.\n"); + #endif + + return False; + } + + fbGetImage((DrawablePtr)pWin, 0, 0, + width, height, format, AllPlanes, data); + + pVisual = nxagentImageVisual((DrawablePtr) pWin, depth); + + if (pVisual == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentFbOnShadowDisplay: WARNING! Visual not found. Using default visual.\n"); + #endif + + pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual; + } + + image = XCreateImage(nxagentDisplay, pVisual, + depth, format, 0, (char *) data, + width, height, BitmapPad(nxagentDisplay), + nxagentImagePad(width, format, 0, depth)); + + if (image == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentFbOnShadowDisplay: XCreateImage failed.\n"); + #endif + + if (data) + { + free(data); + } + + return False; + } + + value.foreground = 0xff0000; + value.background = 0x000000; + value.plane_mask = 0xffffff; + value.fill_style = FillSolid; + + gc = XCreateGC(shadow, win, GCBackground | + GCForeground | GCFillStyle | GCPlaneMask, &value); + + NXCleanImage(image); + + XPutImage(shadow, win, gc, image, 0, 0, 0, 0, width, height); + + XFreeGC(shadow, gc); + + if (image != NULL) + { + XDestroyImage(image); + } + + return True; +} + +#endif + +#ifdef DEBUG + +void nxagentPrintResourceTypes() +{ + fprintf(stderr, "nxagentPrintResourceTypes: RT_PIXMAP [%lu].\n", (unsigned long) RT_PIXMAP); + fprintf(stderr, "nxagentPrintResourceTypes: RT_NX_PIXMAP [%lu].\n", (unsigned long) RT_NX_PIXMAP); + fprintf(stderr, "nxagentPrintResourceTypes: RT_GC [%lu].\n", (unsigned long) RT_GC); + fprintf(stderr, "nxagentPrintResourceTypes: RT_NX_GC [%lu].\n", (unsigned long) RT_NX_GC); + fprintf(stderr, "nxagentPrintResourceTypes: RT_FONT [%lu].\n", (unsigned long) RT_FONT); + fprintf(stderr, "nxagentPrintResourceTypes: RT_NX_FONT [%lu].\n", (unsigned long) RT_NX_FONT); + fprintf(stderr, "nxagentPrintResourceTypes: RT_CURSOR [%lu].\n", (unsigned long) RT_CURSOR); + fprintf(stderr, "nxagentPrintResourceTypes: RT_WINDOW [%lu].\n", (unsigned long) RT_WINDOW); + fprintf(stderr, "nxagentPrintResourceTypes: RT_COLORMAP [%lu].\n", (unsigned long) RT_COLORMAP); +} + +void nxagentPrintResourcePredicate(void *value, XID id, XID type, void *cdata) +{ + fprintf(stderr, "nxagentPrintResourcePredicate: Resource [%p] id [%lu] type [%lu].\n", + (void *) value, (unsigned long) id, (unsigned long) type); +} + +void nxagentPrintResources() +{ + Bool result; + int i; + + nxagentPrintResourceTypes(); + + for (i = 0; i < MAXCLIENTS; i++) + { + if (clients[i]) + { + fprintf(stderr, "nxagentPrintResources: Printing resources for client [%d]:\n", + i); + + FindAllClientResources(clients[i], nxagentPrintResourcePredicate, &result); + } + } +} + +#endif + + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Pixmaps.h b/nx-X11/programs/Xserver/hw/nxagent/Pixmaps.h new file mode 100644 index 000000000..00cc39c5f --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Pixmaps.h @@ -0,0 +1,145 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Pixmap_H__ +#define __Pixmap_H__ + +#include "resource.h" +#include "Split.h" + +extern RESTYPE RT_NX_PIXMAP; + +/* + * Pixmap privates structure. + */ + +typedef struct +{ + Pixmap id; + XID mid; + + Bool isVirtual; + Bool isShared; + + PixmapPtr pVirtualPixmap; + PixmapPtr pRealPixmap; + + void *pPicture; + + RegionPtr corruptedRegion; + + int corruptedBackground; + + int containGlyphs; + int containTrapezoids; + + int usageCounter; + + XID corruptedBackgroundId; + XID corruptedId; + + PixmapPtr synchronizationBitmap; + + Time corruptedTimestamp; + + SplitResourcePtr splitResource; + + int isBackingPixmap; + +} nxagentPrivPixmapRec; + +typedef nxagentPrivPixmapRec *nxagentPrivPixmapPtr; + +extern int nxagentPixmapPrivateIndex; + +/* + * Pixmap privates macro. + */ + +#define nxagentPixmapPriv(pPixmap) \ + ((nxagentPrivPixmapPtr)((pPixmap) -> devPrivates[nxagentPixmapPrivateIndex].ptr)) + +#define nxagentPixmap(pPixmap) (nxagentPixmapPriv(pPixmap) -> id) + +#define nxagentPixmapIsVirtual(pPixmap) \ + (nxagentPixmapPriv(pPixmap) -> isVirtual) + +#define nxagentIsShmPixmap(pPixmap) \ + (nxagentPixmapPriv(pPixmap) -> isShared) + +#define nxagentRealPixmap(pPixmap) \ + (nxagentPixmapPriv(pPixmap) -> pRealPixmap) + +#define nxagentVirtualPixmap(pPixmap) \ + (nxagentPixmapPriv(pPixmap) -> isVirtual ? pPixmap : \ + nxagentPixmapPriv(pPixmap) -> pVirtualPixmap) + +#define nxagentPixmapCorruptedRegion(pPixmap) \ + (nxagentPixmapPriv(nxagentRealPixmap(pPixmap)) -> corruptedRegion) + +#define nxagentPixmapContainGlyphs(pPixmap) \ + (nxagentPixmapPriv(nxagentRealPixmap(pPixmap)) -> containGlyphs) + +#define nxagentPixmapContainTrapezoids(pPixmap) \ + (nxagentPixmapPriv(nxagentRealPixmap(pPixmap)) -> containTrapezoids) + +#define nxagentIsCorruptedBackground(pPixmap) \ + (nxagentPixmapPriv(nxagentRealPixmap(pPixmap)) -> corruptedBackground) + +#define nxagentPixmapUsageCounter(pPixmap) \ + (nxagentPixmapPriv(nxagentRealPixmap(pPixmap)) -> usageCounter) + +#define nxagentPixmapTimestamp(pPixmap) \ + (nxagentPixmapPriv(nxagentRealPixmap(pPixmap)) -> corruptedTimestamp) + +PixmapPtr nxagentPixmapPtr(Pixmap pixmap); + +PixmapPtr nxagentCreatePixmap(ScreenPtr pScreen, int width, + int height, int depth, unsigned usage_hint); + +Bool nxagentDestroyPixmap(PixmapPtr pPixmap); + +RegionPtr nxagentPixmapToRegion(PixmapPtr pPixmap); + +Bool nxagentModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, + int bitsPerPixel, int devKind, void * pPixData); + +RegionPtr nxagentCreateRegion(DrawablePtr pDrawable, GCPtr pGC, int x, int y, + int width, int height); + +void nxagentReconnectPixmap(void *p0, XID x1, void *p2); +Bool nxagentReconnectAllPixmaps(void *p0); +void nxagentDisconnectPixmap(void *p0, XID x1, void* p2); +Bool nxagentDisconnectAllPixmaps(void); + +int nxagentDestroyNewPixmapResourceType(void * p, XID id); + +void nxagentSynchronizeShmPixmap(DrawablePtr pDrawable, int xPict, int yPict, + int wPict, int hPict); + +Bool nxagentPixmapOnShadowDisplay(PixmapPtr pMap); +Bool nxagentFbOnShadowDisplay(); + +#endif /* __Pixmap_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Pointer.c b/nx-X11/programs/Xserver/hw/nxagent/Pointer.c new file mode 100644 index 000000000..c59230724 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Pointer.c @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include "X.h" +#include "Xproto.h" +#include "screenint.h" +#include "input.h" +#include "misc.h" +#include "scrnintstr.h" +#include "servermd.h" +#include "mipointer.h" + +#include "Agent.h" +#include "Args.h" +#include "Display.h" +#include "Screen.h" +#include "Pointer.h" +#include "Events.h" +#include "Options.h" + +#include "compext/Compext.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * The nxagentReversePointerMap array is used to + * memorize remote display pointer map. + */ + +unsigned char nxagentReversePointerMap[MAXBUTTONS]; + +void nxagentChangePointerControl(DeviceIntPtr pDev, PtrCtrl *ctrl) +{ + /* + * The original behaviour was to reset the pointer settings + * (acceleration and alas) to the default values. What the + * average user expects, on the contrary, is to have agent + * inheriting whatever value is set on the real X display. + * Having to reflect changes made inside the agent session, + * the correct behavior would be saving the original values + * and restoring them as soon as focus leaves the agent's + * window. + */ + + if (nxagentOption(DeviceControl) == True) + { + #ifdef TEST + fprintf(stderr, "nxagentChangePointerControl: WARNING! Propagating changes to pointer settings.\n"); + #endif + + XChangePointerControl(nxagentDisplay, True, True, + ctrl->num, ctrl->den, ctrl->threshold); + + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentChangePointerControl: WARNING! Not propagating changes to pointer settings.\n"); + #endif +} + +int nxagentPointerProc(DeviceIntPtr pDev, int onoff) +{ + CARD8 map[MAXBUTTONS]; + int nmap; + int i; + + switch (onoff) + { + case DEVICE_INIT: + + #ifdef TEST + fprintf(stderr, "nxagentPointerProc: Called for [DEVICE_INIT].\n"); + #endif + + if (NXDisplayError(nxagentDisplay) == 1) + { + return Success; + } + + nmap = XGetPointerMapping(nxagentDisplay, map, MAXBUTTONS); + for (i = 0; i <= nmap; i++) + map[i] = i; /* buttons are already mapped */ + InitPointerDeviceStruct((DevicePtr) pDev, map, nmap, + miPointerGetMotionEvents, + nxagentChangePointerControl, + miPointerGetMotionBufferSize()); + break; + case DEVICE_ON: + + #ifdef TEST + fprintf(stderr, "nxagentPointerProc: Called for [DEVICE_ON].\n"); + #endif + + if (NXDisplayError(nxagentDisplay) == 1) + { + return Success; + } + + nxagentInitPointerMap(); + + nxagentEnablePointerEvents(); + + break; + + case DEVICE_OFF: + + #ifdef TEST + fprintf(stderr, "nxagentPointerProc: Called for [DEVICE_OFF].\n"); + #endif + + if (NXDisplayError(nxagentDisplay) == 1) + { + return Success; + } + + nxagentDisablePointerEvents(); + + break; + + case DEVICE_CLOSE: + + #ifdef TEST + fprintf(stderr, "nxagentPointerProc: Called for [DEVICE_CLOSE].\n"); + #endif + + break; + } + + return Success; +} + +void nxagentInitPointerMap(void) +{ + int numButtons; + + int i; + + unsigned char pointerMap[MAXBUTTONS]; + + #ifdef DEBUG + fprintf(stderr, "nxagentInitPointerMap: Going to retrieve the " + "pointer map from remote display.\n"); + #endif + + numButtons = XGetPointerMapping(nxagentDisplay, pointerMap, MAXBUTTONS); + + /* + * Computing revers pointer map. + */ + + for (i = 1; i <= numButtons; i++) + { + nxagentReversePointerMap[pointerMap[i - 1]] = i; + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Pointer.h b/nx-X11/programs/Xserver/hw/nxagent/Pointer.h new file mode 100644 index 000000000..85162d4a5 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Pointer.h @@ -0,0 +1,62 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Pointer_H__ +#define __Pointer_H__ + +#define MAXBUTTONS 256 + +#define NXAGENT_POINTER_EVENT_MASK \ + (ButtonPressMask | ButtonReleaseMask | PointerMotionMask | \ + EnterWindowMask | LeaveWindowMask) + +/* + * The nxagentReversePointerMap array is used to + * memorize remote display pointer map. + */ + +extern unsigned char nxagentReversePointerMap[MAXBUTTONS]; + +void nxagentChangePointerControl(DeviceIntPtr pDev, PtrCtrl *ctrl); + +int nxagentPointerProc(DeviceIntPtr pDev, int onoff); + +void nxagentInitPointerMap(void); + +#endif /* __Pointer_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c new file mode 100644 index 000000000..fb2303549 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.c @@ -0,0 +1,849 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <signal.h> + +#include "X.h" +#include "Xproto.h" +#include "Xpoll.h" +#include "mi.h" +#include "fb.h" +#include "inputstr.h" + +#include "Agent.h" +#include "Atoms.h" +#include "Drawable.h" +#include "Client.h" +#include "Reconnect.h" +#include "Display.h" +#include "Dialog.h" +#include "Screen.h" +#include "Windows.h" +#include "Events.h" +#include "Dialog.h" +#include "Args.h" +#include "Font.h" +#include "GCs.h" +#include "Trap.h" +#include "Keyboard.h" +#include "Composite.h" +#include "Millis.h" +#include "Splash.h" +#include "Error.h" +#include "Keystroke.h" + +#ifdef XKB +#include "XKBsrv.h" +#endif + +#include <nx/NX.h> +#include "compext/Compext.h" +#include <nx/NXalert.h> + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define NXAGENT_RECONNECT_DEFAULT_MESSAGE_SIZE 32 + +extern Bool nxagentReconnectAllCursor(void*); +extern Bool nxagentReconnectAllColormap(void*); +extern Bool nxagentReconnectAllWindows(void*); +extern Bool nxagentReconnectAllGlyphSet(void*); +extern Bool nxagentReconnectAllPictFormat(void*); +extern Bool nxagentReconnectAllPicture(void*); + +extern Bool nxagentDisconnectAllPicture(void); +extern Bool nxagentDisconnectAllWindows(void); +extern Bool nxagentDisconnectAllCursor(void); + +extern Bool nxagentReconnectFailedFonts(void*); +extern Bool nxagentInstallFontServerPath(void); +extern Bool nxagentUninstallFontServerPath(void); + +extern void nxagentRemoveXConnection(void); + +extern void nxagentInitPointerMap(void); + +static char *nxagentGetReconnectError(void); + +void nxagentInitializeRecLossyLevel(void); + +static char *nxagentReconnectErrorMessage = NULL; +static int nxagentReconnectErrorId; + +extern Bool nxagentRenderEnable; + +extern char *nxagentKeyboard; + +enum SESSION_STATE nxagentSessionState = SESSION_STARTING; + +struct nxagentExceptionStruct nxagentException = {0, 0}; + +enum RECONNECTION_STEP +{ + DISPLAY_STEP = 0, + SCREEN_STEP, + FONT_STEP, + PIXMAP_STEP, + GC_STEP, + CURSOR_STEP, + COLORMAP_STEP, + WINDOW_STEP, + GLYPHSET_STEP, + PICTFORMAT_STEP, + PICTURE_STEP, + STEP_NONE +}; + +void *reconnectLossyLevel[STEP_NONE]; + +static enum RECONNECTION_STEP failedStep; + +#include <limits.h> + +/* + * Path of state File + */ +char stateFile[PATH_MAX]; + + +void setStatePath(char* path) +{ + strncpy(stateFile, path, PATH_MAX-1); +} + +void saveAgentState(char* state) +{ + FILE* fptr; + if(strlen(stateFile)) + { + fptr=fopen(stateFile, "w"); + if(!fptr) + return; + fprintf(fptr,"%s", state); + fclose(fptr); + } +} + + +int nxagentHandleConnectionStates(void) +{ + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Handling Exception with " + "state [%s] and transport [%d] and generation [%ld].\n", + DECODE_SESSION_STATE(nxagentSessionState), NXTransRunning(NX_FD_ANY), serverGeneration); + fprintf(stderr, "nxagentHandleConnectionStates: Entering with nxagentException.sigHup = [%d], " + "nxagentException.ioError = [%d]\n", + nxagentException.sigHup, nxagentException.ioError); + #endif + + if (nxagentException.sigHup > 0) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Got SIGHUP in the exception flags.\n"); + #endif + + nxagentException.sigHup = 0; + + if (nxagentSessionState == SESSION_UP) + { + if (nxagentOption(Persistent)) + { + nxagentSessionState = SESSION_GOING_DOWN; + + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Handling " + "signal [SIGHUP] by disconnecting the agent.\n"); + + #endif + + } + else + { + nxagentTerminateSession(); + } + } + else if (nxagentSessionState == SESSION_STARTING) + { + nxagentTerminateSession(); + + #ifdef WARNING + fprintf(stderr, "nxagentHandleConnectionStates: Handling signal [SIGHUP] by terminating the agent.\n"); + #endif + } + else if (nxagentSessionState == SESSION_DOWN && + NXTransRunning(NX_FD_ANY) == 0) + { + nxagentSessionState = SESSION_GOING_UP; + + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Handling signal [SIGHUP] by reconnecting the agent.\n"); + #endif + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Handling signal with state [%s] and exception [%d].\n", + DECODE_SESSION_STATE(nxagentSessionState), dispatchException); + #endif + } + } + + if (nxagentNeedConnectionChange() == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Calling nxagentHandleConnectionChanges " + "with ioError [%d] sigHup [%d].\n", nxagentException.ioError, nxagentException.sigHup); + #endif + + nxagentHandleConnectionChanges(); + } + + if (nxagentException.ioError > 0) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error in the exception flags.\n"); + #endif +/* +TODO: This should be reset only when + the state became SESSION_DOWN. +*/ + nxagentException.ioError = 0; + + if (nxagentOption(Persistent) == 1 && nxagentSessionState != SESSION_STARTING) + { + if (nxagentSessionState == SESSION_UP) + { + if ((dispatchException & DE_TERMINATE) == 0) + { + fprintf(stderr, "Session: Display failure detected at '%s'.\n", GetTimeAsString()); + + fprintf(stderr, "Session: Suspending session at '%s'.\n", GetTimeAsString()); + saveAgentState("SUSPENDING"); + } + + nxagentDisconnectSession(); + } + else if (nxagentSessionState == SESSION_GOING_DOWN) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error with session " + "[SESSION_GOING_DOWN].\n"); + #endif + } + else if (nxagentSessionState == SESSION_GOING_UP) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error with session " + "[SESSION_GOING_UP].\n"); + #endif + + nxagentSessionState = SESSION_GOING_DOWN; + + nxagentSetReconnectError(FAILED_RESUME_DISPLAY_BROKEN_ALERT, + "Got I/O error during reconnect."); + + nxagentChangeOption(Fullscreen, False); + + return 1; + } + else if (nxagentSessionState == SESSION_DOWN) + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error with session " + "[SESSION_DOWN]. Ignoring.\n"); + #endif + + return 1; + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionStates: Got I/O error with session " + "[%d].\n", nxagentSessionState); + #endif + } + + nxagentSessionState = SESSION_DOWN; + + if ((dispatchException & DE_TERMINATE) == 0) + { + #ifdef NX_DEBUG_INPUT + fprintf(stderr, "Session: Session suspended at '%s' timestamp [%lu].\n", GetTimeAsString(), GetTimeInMillis()); + #else + fprintf(stderr, "Session: Session suspended at '%s'.\n", GetTimeAsString()); + #endif + } + saveAgentState("SUSPENDED"); + + nxagentResetDisplayHandlers(); + + return 1; + } + + fprintf(stderr, "Info: Disconnected from display '%s'.\n", nxagentDisplayName); + + nxagentTerminateSession(); + + return -1; + } + + return 0; +} + +void nxagentInitializeRecLossyLevel() +{ + *(int *)reconnectLossyLevel[DISPLAY_STEP] = 0; + *(int *)reconnectLossyLevel[SCREEN_STEP] = 0; + *(int *)reconnectLossyLevel[FONT_STEP] = 0; + *(int *)reconnectLossyLevel[PIXMAP_STEP] = 0; + *(int *)reconnectLossyLevel[GC_STEP] = 0; + *(int *)reconnectLossyLevel[CURSOR_STEP] = 0; + *(int *)reconnectLossyLevel[COLORMAP_STEP] = 0; + *(int *)reconnectLossyLevel[WINDOW_STEP] = 0; + *(int *)reconnectLossyLevel[GLYPHSET_STEP] = 0; + *(int *)reconnectLossyLevel[PICTFORMAT_STEP] = 0; + *(int *)reconnectLossyLevel[PICTURE_STEP] = 0; +} + +void nxagentInitReconnector(void) +{ + nxagentReconnectTrap = 0; + + reconnectLossyLevel[DISPLAY_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[SCREEN_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[FONT_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[PIXMAP_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[GC_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[CURSOR_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[COLORMAP_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[WINDOW_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[GLYPHSET_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[PICTFORMAT_STEP] = malloc(sizeof(int)); + reconnectLossyLevel[PICTURE_STEP] = malloc(sizeof(int)); +} + +void nxagentDisconnectSession(void) +{ + #ifdef TEST + fprintf(stderr, "nxagentDisconnectSession: Disconnecting session with state [%s].\n", + DECODE_SESSION_STATE(nxagentSessionState)); + #endif + + /* + * Force an I/O error on the display + * and wait until the NX transport + * is gone. + */ + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectSession: Disconnecting the X display.\n"); + #endif + + nxagentWaitDisplay(); + + /* + * Prepare for the next reconnection. + */ + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectSession: Disconnecting all X resources.\n"); + #endif + + nxagentInitializeRecLossyLevel(); + + nxagentBackupDisplayInfo(); + + if (nxagentOption(Rootless)) + { + nxagentFreePropertyList(); + } + + if (nxagentRenderEnable) + { + nxagentDisconnectAllPicture(); + } + + nxagentEmptyAllBackingStoreRegions(); + + nxagentDisconnectAllWindows(); + nxagentDisconnectAllCursor(); + nxagentDisconnectAllPixmaps(); + nxagentDisconnectAllGCs(); + nxagentDisconnectDisplay(); + + nxagentWMIsRunning = 0; + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectSession: Disconnection completed. SigHup is [%d]. IoError is [%d].\n", + nxagentException.sigHup, nxagentException.ioError); + #endif +} + +Bool nxagentReconnectSession(void) +{ + char *nxagentOldKeyboard = NULL; + + nxagentResizeDesktopAtStartup = False; + + /* + * Propagate device settings if explicitly asked for. + */ + + nxagentChangeOption(DeviceControl, nxagentOption(DeviceControlUserDefined)); + + /* + * We need to zero out every new XID + * created by the disconnected display. + */ + + nxagentDisconnectSession(); + + /* + * Set this in order to let the screen + * function to behave differently at + * reconnection time. + */ + + nxagentReconnectTrap = True; + + nxagentSetReconnectError(0, NULL); + + if (nxagentKeyboard != NULL) + { + nxagentOldKeyboard = strndup(nxagentKeyboard, strlen(nxagentKeyboard)); + if (nxagentOldKeyboard == NULL) + { + /* 0 means reconnection failed */ + return 0; + } + + free(nxagentKeyboard); + nxagentKeyboard = NULL; + } + + nxagentSaveOptions(); + + nxagentResetOptions(); + + nxagentProcessOptionsFile(); + + if (nxagentReconnectDisplay(reconnectLossyLevel[DISPLAY_STEP]) == 0) + { + failedStep = DISPLAY_STEP; + + #ifdef TEST + fprintf(stderr, "nxagentReconnect: WARNING! Failed display reconnection.\n"); + #endif + + goto nxagentReconnectError; + } + + if (nxagentReconnectScreen(reconnectLossyLevel[SCREEN_STEP]) == 0) + { + failedStep = SCREEN_STEP; + + goto nxagentReconnectError; + } + + nxagentDisconnectAllFonts(); + + nxagentListRemoteFonts("*", nxagentMaxFontNames); + + if (nxagentReconnectAllFonts(reconnectLossyLevel[FONT_STEP]) == 0) + { + if (nxagentReconnectFailedFonts(reconnectLossyLevel[FONT_STEP]) == 0) + { + failedStep = FONT_STEP; + + goto nxagentReconnectError; + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentReconnect: WARNING! Unable to retrieve all the fonts currently in use. " + "Missing fonts have been replaced.\n"); + #endif + + nxagentLaunchDialog(DIALOG_FONT_REPLACEMENT); + } + } + + /* + * Map the main window and send a + * SetSelectionOwner request to + * notify of the agent start. + */ + + nxagentMapDefaultWindows(); + + /* + * Ensure that the SetSelectionOwner + * request is sent through the link. + */ + + XFlush(nxagentDisplay); + + NXTransContinue(NULL); + + nxagentEmptyBSPixmapList(); + + if (nxagentReconnectAllPixmaps(reconnectLossyLevel[PIXMAP_STEP]) == 0) + { + failedStep = PIXMAP_STEP; + + goto nxagentReconnectError; + } + + if (nxagentReconnectAllGCs(reconnectLossyLevel[GC_STEP]) == 0) + { + failedStep = GC_STEP; + + goto nxagentReconnectError; + } + + if (nxagentReconnectAllColormap(reconnectLossyLevel[COLORMAP_STEP]) == 0) + { + failedStep = COLORMAP_STEP; + + goto nxagentReconnectError; + } + + if (nxagentReconnectAllWindows(reconnectLossyLevel[WINDOW_STEP]) == 0) + { + failedStep = WINDOW_STEP; + + goto nxagentReconnectError; + } + + if (nxagentRenderEnable) + { + if (nxagentReconnectAllGlyphSet(reconnectLossyLevel[GLYPHSET_STEP]) == 0) + { + failedStep = GLYPHSET_STEP; + + goto nxagentReconnectError; + } + + if (nxagentReconnectAllPictFormat(reconnectLossyLevel[PICTFORMAT_STEP]) == 0) + { + failedStep = PICTFORMAT_STEP; + + goto nxagentReconnectError; + } + + if (nxagentReconnectAllPicture(reconnectLossyLevel[PICTURE_STEP]) == 0) + { + failedStep = PICTURE_STEP; + + goto nxagentReconnectError; + } + } + + if (nxagentReconnectAllCursor(reconnectLossyLevel[CURSOR_STEP]) == 0) + { + failedStep = CURSOR_STEP; + + goto nxagentReconnectError; + } + + if (nxagentSetWindowCursors(reconnectLossyLevel[WINDOW_STEP]) == 0) + { + failedStep = WINDOW_STEP; + + goto nxagentReconnectError; + } + + if (nxagentOption(ResetKeyboardAtResume) == 1 && + (nxagentKeyboard == NULL || nxagentOldKeyboard == NULL || + strcmp(nxagentKeyboard, nxagentOldKeyboard) != 0 || + strcmp(nxagentKeyboard, "query") == 0)) + { + if (nxagentResetKeyboard() == 0) + { + #ifdef WARNING + if (nxagentVerbose == 1) + { + fprintf(stderr, "nxagentReconnect: Failed to reset keyboard device.\n"); + } + #endif + + failedStep = WINDOW_STEP; + + goto nxagentReconnectError; + } + } + else + { + nxagentResetKeycodeConversion(); + } + + nxagentXkbState.Initialized = 0; + + if (nxagentOldKeyboard != NULL) + { + free(nxagentOldKeyboard); + + nxagentOldKeyboard = NULL; + } + + nxagentInitPointerMap(); + + nxagentDeactivatePointerGrab(); + + nxagentWakeupByReconnect(); + + nxagentFreeGCList(); + + nxagentRedirectDefaultWindows(); + + if (nxagentResizeDesktopAtStartup || nxagentOption(Rootless) == True || nxagentOption(Xinerama) == True) + { + nxagentChangeScreenConfig(0, nxagentOption(RootWidth), + nxagentOption(RootHeight), 0, 0); + + nxagentResizeDesktopAtStartup = False; + } + + nxagentReconnectTrap = False; + + nxagentExposeArrayIsInitialized = False; + + if (nxagentSessionState != SESSION_GOING_UP) + { + #ifdef WARNING + fprintf(stderr, "nxagentReconnect: WARNING! Unexpected session state [%s] while reconnecting.\n", + DECODE_SESSION_STATE(nxagentSessionState)); + #endif + + goto nxagentReconnectError; + } + + /* Re-read keystrokes definitions in case the keystrokes file has + changed while being supended */ + nxagentInitKeystrokes(True); + + #ifdef NX_DEBUG_INPUT + fprintf(stderr, "Session: Session resumed at '%s' timestamp [%lu].\n", GetTimeAsString(), GetTimeInMillis()); + #else + fprintf(stderr, "Session: Session resumed at '%s'.\n", GetTimeAsString()); + #endif + saveAgentState("RUNNING"); + + nxagentRemoveSplashWindow(NULL); + + /* + * We let the proxy flush the link on our behalf + * after having opened the display. We are now + * entering again the dispatcher so can flush + * the link explicitly. + */ + + #ifdef TEST + fprintf(stderr, "nxagentReconnect: Setting the NX flush policy to deferred.\n"); + #endif + + NXSetDisplayPolicy(nxagentDisplay, NXPolicyDeferred); + + nxagentCleanupBackupDisplayInfo(); + + return 1; + +nxagentReconnectError: + + if (failedStep == DISPLAY_STEP) + { + #ifdef TEST + fprintf(stderr, "nxagentReconnect: Reconnection failed in display step. Restoring options.\n"); + #endif + + nxagentRestoreOptions(); + } + else + { + nxagentCleanupBackupDisplayInfo(); + } + + if (*nxagentGetReconnectError() == '\0') + { + #ifdef WARNING + if (nxagentVerbose == 1) + { + fprintf(stderr, "nxagentReconnect: WARNING! The reconnect error message is not set. Failed step is [%d].\n", + failedStep); + } + #endif + + #ifdef TEST + fprintf(stderr, "nxagentReconnect: Reconnection failed due to a display error.\n"); + #endif + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentReconnect: Reconnection failed with reason '%s'\n", + nxagentGetReconnectError()); + #endif + } + + if (NXDisplayError(nxagentDisplay) == 0) + { + nxagentUnmapWindows(); + + nxagentFailedReconnectionDialog(nxagentReconnectErrorId, nxagentGetReconnectError()); + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentReconnect: Cannot launch the dialog without a valid display.\n"); + } + #endif + + if (failedStep == FONT_STEP) + { + *((int *) reconnectLossyLevel[FONT_STEP]) = 1; + } + + if (nxagentDisplay == NULL) + { + nxagentDisconnectDisplay(); + } + + if (nxagentOldKeyboard != NULL) + { + free(nxagentOldKeyboard); + + nxagentOldKeyboard = NULL; + } + + return 0; +} + +void nxagentSetReconnectError(int id, char *format, ...) +{ + static int size = 0; + + va_list ap; + int n; + + if (format == NULL) + { + nxagentSetReconnectError(id, ""); + + return; + } + + nxagentReconnectErrorId = id; + + while (1) + { + va_start (ap, format); + + n = vsnprintf(nxagentReconnectErrorMessage, size, format, ap); + + va_end(ap); + + if (n > -1 && n < size) + { + break; + } + if (n > -1) + { + size = n + 1; + } + else + { + /* + * The vsnprintf() in glibc 2.0.6 would return + * -1 when the output was truncated. See section + * NOTES on printf(3). + */ + + size = (size ? size * 2 : NXAGENT_RECONNECT_DEFAULT_MESSAGE_SIZE); + } + + nxagentReconnectErrorMessage = realloc(nxagentReconnectErrorMessage, size); + + if (nxagentReconnectErrorMessage == NULL) + { + FatalError("realloc failed"); + } + } + + return; +} + +static char* nxagentGetReconnectError() +{ + if (nxagentReconnectErrorMessage == NULL) + { + nxagentSetReconnectError(nxagentReconnectErrorId, ""); + } + + return nxagentReconnectErrorMessage; +} + +void nxagentHandleConnectionChanges() +{ + #ifdef TEST + fprintf(stderr, "nxagentHandleConnectionChanges: Called.\n"); + #endif + + if (nxagentSessionState == SESSION_GOING_DOWN) + { + fprintf(stderr, "Session: Suspending session at '%s'.\n", GetTimeAsString()); + saveAgentState("SUSPENDING"); + + nxagentDisconnectSession(); + } + else if (nxagentSessionState == SESSION_GOING_UP) + { + fprintf(stderr, "Session: Resuming session at '%s'.\n", GetTimeAsString()); + saveAgentState("RESUMING"); + + if (nxagentReconnectSession()) + { + nxagentSessionState = SESSION_UP; + } + else + { + nxagentSessionState = SESSION_GOING_DOWN; + + fprintf(stderr, "Session: Display failure detected at '%s'.\n", GetTimeAsString()); + + fprintf(stderr, "Session: Suspending session at '%s'.\n", GetTimeAsString()); + saveAgentState("SUSPENDING"); + + nxagentDisconnectSession(); + } + } +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Reconnect.h b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.h new file mode 100644 index 000000000..d1c62166b --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Reconnect.h @@ -0,0 +1,78 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Reconnect_H__ +#define __Reconnect_H__ + +extern Display *nxagentDisplayState; + +struct nxagentExceptionStruct +{ + int sigHup; + int ioError; +}; + +extern struct nxagentExceptionStruct nxagentException; + +void nxagentSetReconnectError(int id, char *format, ...); + +void nxagentInitReconnector(void); +Bool nxagentReconnectSession(void); +int nxagentHandleConnectionStates(void); +void nxagentHandleConnectionChanges(void); +void setStatePath(char*); +void saveAgentState(char*); + +enum SESSION_STATE +{ + SESSION_STARTING, + SESSION_UP, + SESSION_DOWN, + SESSION_GOING_DOWN, + SESSION_GOING_UP +}; + +extern enum SESSION_STATE nxagentSessionState; + +#define DECODE_SESSION_STATE(state) \ + ((state) == SESSION_STARTING ? "SESSION_STARTING" : \ + (state) == SESSION_UP ? "SESSION_UP" : \ + (state) == SESSION_GOING_UP? "SESSION_GOING_UP" : \ + (state) == SESSION_DOWN ? "SESSION_DOWN" : \ + (state) == SESSION_GOING_DOWN? "SESSION_GOING_DOWN" : \ + "UNKNOWN") + +/* + * Use this macro in the block and wakeup + * handlers to save a function call. + */ + +#define nxagentNeedConnectionChange() \ + (nxagentSessionState == SESSION_GOING_DOWN || \ + nxagentSessionState == SESSION_GOING_UP) + +void nxagentDisconnectSession(void); + +#endif /* __Reconnect_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Render.c b/nx-X11/programs/Xserver/hw/nxagent/Render.c new file mode 100644 index 000000000..753134eb3 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Render.c @@ -0,0 +1,3047 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "picturestr.h" +#include "glyphstr.h" + +#include "Render.h" + +#include "X.h" +#include "Xproto.h" + +#include "render.h" +#include "renderproto.h" + +#include "mi.h" +#include "fb.h" +#include "mipict.h" +#include "fbpict.h" +#include "dixstruct.h" +#include "protocol-versions.h" + +#include "Agent.h" +#include "Drawable.h" +#include "Trap.h" +#include "Args.h" + +#define Atom XlibAtom +#define Pixmap XlibPixmap +#include "X11/include/Xrenderint_nxagent.h" +#undef Atom +#undef Pixmap + +#include "region.h" +#include <X11/extensions/extutil.h> + +#include "Display.h" +#include "Pixmaps.h" +#include "Cursor.h" +#include "Client.h" +#include "Image.h" +#include "Pixels.h" +#include "Handlers.h" + +#include <nx/NXproto.h> + +#define MAX_FORMATS 255 + +#define NXAGENT_PICTURE_ALWAYS_POINTS_TO_VIRTUAL + +/* + * Define if you want split multiple glyph lists + * into multiple RenderCompositeGlyphs requests. + */ + +#undef SPLIT_GLYPH_LISTS + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* +FIXME: Most operations don't seem to produce any visible result + but still generate tons of traffic. +*/ +#undef SKIP_LOUSY_RENDER_OPERATIONS +#undef SKIP_REALLY_ALL_LOUSY_RENDER_OPERATIONS + +/* + * Do we split the big trapezoid requests? + */ + +#define TRAPEZOIDS_PER_REQUEST 256 + +/* + * Margin added around the glyphs extent (in pixels). + */ + +#define GLYPH_BOX_MARGIN 2 + +int nxagentRenderEnable = UNDEFINED; +int nxagentRenderVersionMajor; +int nxagentRenderVersionMinor; + +int nxagentPicturePrivateIndex = 0; + +static int nxagentNumFormats = 0; + +static XRenderPictFormat nxagentArrayFormats[MAX_FORMATS]; + +XRenderPictFormat *nxagentMatchingFormats(PictFormatPtr pForm); + +BoxPtr nxagentGlyphsExtents; +BoxPtr nxagentTrapezoidExtents; + +#ifdef DEBUG + +static void nxagentPrintFormat(XRenderPictFormat *pFormat); + +#endif + +/* + * From NXglyph.c. + */ + +extern const CARD8 glyphDepths[]; + +/* + * From BitmapUtils.c. + */ + +extern void nxagentBitOrderInvert(unsigned char *data, int nbytes); + +/* + * Other functions defined here. + */ + +void nxagentQueryFormats(void); + +void nxagentCreateGlyphSet(GlyphSetPtr pGly); + +int nxagentCursorSaveRenderInfo(ScreenPtr pScreen, CursorPtr pCursor); + +void nxagentCursorPostSaveRenderInfo(CursorPtr pCursor, ScreenPtr pScreen, + PicturePtr pPicture, int x, int y); + +int nxagentCreatePicture(PicturePtr pPicture, Mask mask); + +int nxagentChangePictureClip(PicturePtr pPicture, int clipType, int nRects, + xRectangle *rects, int xOrigin, int yOrigin); + +void nxagentDestroyPictureClip(PicturePtr pPicture); + +void nxagentValidatePicture(PicturePtr pPicture, Mask mask); + +void nxagentComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, + INT16 yDst, CARD16 width, CARD16 height); + +void nxagentGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists, + XGlyphElt8 *elts, int sizeID, GlyphPtr *glyphsBase); + +void nxagentCompositeRects(CARD8 op, PicturePtr pDst, xRenderColor *color, + int nRect, xRectangle *rects); + +void nxagentTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps); + +void nxagentRasterizeTrapezoid(PicturePtr pMask, xTrapezoid *trap, + int x_off, int y_off); + +void nxagentTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tris); + +void nxagentTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int npoint, xPointFixed *points); + +void nxagentChangePicture(PicturePtr pPicture, Mask mask); + +void nxagentTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int npoint, xPointFixed *points); + +void nxagentReferenceGlyphSet(GlyphSetPtr glyphSet); + +void nxagentFreeGlyphs(GlyphSetPtr glyphSet, CARD32 *gids, int nglyph); + +void nxagentFreeGlyphSet(GlyphSetPtr glyphSet); + +void nxagentSetPictureTransform(PicturePtr pPicture, void * transform); + +void nxagentSetPictureFilter(PicturePtr pPicture, char *filter, int name_size, + void * params, int nparams); + +Bool nxagentReconnectAllGlyphSet(void *p); + +Bool nxagentReconnectAllPicture(void *); + +Bool nxagentDisconnectAllPicture(void); + +void nxagentRenderExtensionInit() +{ + int first_event, first_error; + int major_version, minor_version; + + if (XRenderQueryExtension(nxagentDisplay, &first_event, &first_error)) + { + XRenderQueryVersion(nxagentDisplay, &major_version, &minor_version); + + /* + * As the RENDER requests are passed directly to + * the remote X server this can cause problems if + * our RENDER version is different from the version + * supported by the remote. For this reasos let's + * advertise to our clients the lowest between the + + two versions. + */ + + if (major_version > SERVER_RENDER_MAJOR_VERSION || + (major_version == SERVER_RENDER_MAJOR_VERSION && + minor_version > SERVER_RENDER_MINOR_VERSION)) + { + #ifdef TEST + fprintf(stderr, "nxagentRenderExtensionInit: Using render version [%d.%d] with " + "remote version [%d.%d].\n", SERVER_RENDER_MAJOR_VERSION, SERVER_RENDER_MINOR_VERSION, + major_version, minor_version); + #endif + + nxagentRenderVersionMajor = SERVER_RENDER_MAJOR_VERSION; + nxagentRenderVersionMinor = SERVER_RENDER_MINOR_VERSION; + } + else if (major_version < SERVER_RENDER_MAJOR_VERSION || + (major_version == SERVER_RENDER_MAJOR_VERSION && + minor_version < SERVER_RENDER_MINOR_VERSION)) + { + #ifdef TEST + fprintf(stderr, "Info: Local render version %d.%d is higher " + "than remote version %d.%d.\n", SERVER_RENDER_MAJOR_VERSION, SERVER_RENDER_MINOR_VERSION, + major_version, minor_version); + + fprintf(stderr, "Info: Lowering the render version reported to clients.\n"); + #endif + + nxagentRenderVersionMajor = major_version; + nxagentRenderVersionMinor = minor_version; + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentRenderExtensionInit: Local render version %d.%d " + "matches remote version %d.%d.\n", SERVER_RENDER_MAJOR_VERSION, SERVER_RENDER_MINOR_VERSION, + major_version, minor_version); + #endif + + nxagentRenderVersionMajor = major_version; + nxagentRenderVersionMinor = minor_version; + } + } + else + { + #ifdef WARNING + fprintf(stderr, "Warning: Render not available on the remote display.\n"); + #endif + + nxagentRenderEnable = False; + } +} + +int nxagentCursorSaveRenderInfo(ScreenPtr pScreen, CursorPtr pCursor) +{ + pCursor -> devPriv[pScreen -> myNum] = malloc(sizeof(nxagentPrivCursor)); + + if (nxagentCursorPriv(pCursor, pScreen) == NULL) + { + FatalError("malloc failed"); + } + + nxagentCursorUsesRender(pCursor, pScreen) = 1; + nxagentCursorPicture(pCursor, pScreen) = NULL; + + return 1; +} + +void nxagentCursorPostSaveRenderInfo(CursorPtr pCursor, ScreenPtr pScreen, + PicturePtr pPicture, int x, int y) +{ + nxagentCursorPicture(pCursor, pScreen) = pPicture; + nxagentCursorXOffset(pCursor, pScreen) = x; + nxagentCursorYOffset(pCursor, pScreen) = y; +} + +int nxagentRenderRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + int cid; + int x, y; + + PicturePtr pPicture; + + pPicture = nxagentCursorPicture(pCursor, pScreen); + + pPicture -> refcnt++; + + x = nxagentCursorXOffset(pCursor, pScreen); + y = nxagentCursorYOffset(pCursor, pScreen); + + /* + * Set the lossless trap so that the image functions + * will not try to encode the image using a lossy + * compression. Drawables should have a quality flag, + * telling if they were originally encoded with a + * lossy algorithm. This would allow us to skip the + * synchronization if the cursor was already encoded + * with the best quality. + */ + + #ifdef TEST + fprintf(stderr, "nxagentRenderRealizeCursor: Forcing the synchronization " + "of the cursor.\n"); + #endif + + nxagentMarkCorruptedRegion(pPicture -> pDrawable, NULL); + + nxagentLosslessTrap = 1; + + nxagentSynchronizeDrawable(pPicture -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + + nxagentLosslessTrap = 0; + + cid = XRenderCreateCursor(nxagentDisplay, nxagentPicture(pPicture), x, y); + + nxagentCursor(pCursor, pScreen) = cid; + + return 1; +} + +int nxagentCreatePicture(PicturePtr pPicture, Mask mask) +{ + XRenderPictureAttributes attributes; + unsigned long valuemask=0; + XRenderPictFormat *pForm; + + Picture id; + + #ifdef DEBUG + fprintf(stderr, "nxagentCreatePicture: Function called with picture at [%p] and mask [%ld].\n", + (void *) pPicture, mask); + #endif + + if (pPicture == NULL) + { + return 0; + } + + #ifdef DEBUG + + if (pPicture -> pDrawable -> type == DRAWABLE_PIXMAP) + { + if (nxagentIsShmPixmap((PixmapPtr)pPicture -> pDrawable)) + { + fprintf (stderr, "nxagentCreatePicture: Picture uses a shared pixmap.\n"); + } + else + { + fprintf (stderr, "nxagentCreatePicture: Picture uses a plain pixmap.\n"); + } + } + else + { + fprintf (stderr, "nxagentCreatePicture: Picture uses a window.\n"); + } + + #endif + + /* + * All the picture default values are 0. + */ + + memset(&(nxagentPicturePriv(pPicture) -> lastServerValues), 0, sizeof(XRenderPictureAttributes)); + + if (mask & CPRepeat) + { + attributes.repeat = (Bool)pPicture -> repeat; + + valuemask |= CPRepeat; + + nxagentSetPictureRemoteValue(pPicture, repeat, attributes.repeat); + } + + if (mask & CPAlphaMap) + { + attributes.alpha_map = nxagentPicturePriv(pPicture -> alphaMap) -> picture; + + valuemask |= CPAlphaMap; + + nxagentSetPictureRemoteValue(pPicture, alpha_map, attributes.alpha_map); + } + + if (mask & CPAlphaXOrigin) + { + attributes.alpha_x_origin = pPicture -> alphaOrigin.x; + + valuemask |= CPAlphaXOrigin; + + nxagentSetPictureRemoteValue(pPicture, alpha_x_origin, attributes.alpha_x_origin); + } + + if (mask & CPAlphaYOrigin) + { + attributes.alpha_y_origin = pPicture -> alphaOrigin.y; + + valuemask |= CPAlphaYOrigin; + + nxagentSetPictureRemoteValue(pPicture, alpha_y_origin, attributes.alpha_y_origin); + } + + if (mask & CPClipXOrigin) + { + attributes.clip_x_origin = pPicture -> clipOrigin.x; + + valuemask |= CPClipXOrigin; + + nxagentSetPictureRemoteValue(pPicture, clip_x_origin, attributes.clip_x_origin); + } + + if (mask & CPClipYOrigin) + { + attributes.clip_y_origin = pPicture -> clipOrigin.y; + + valuemask |= CPClipYOrigin; + + nxagentSetPictureRemoteValue(pPicture, clip_y_origin, attributes.clip_y_origin); + } + + if (mask & CPGraphicsExposure) + { + attributes.graphics_exposures = (Bool)pPicture -> graphicsExposures; + + valuemask |= CPGraphicsExposure; + + nxagentSetPictureRemoteValue(pPicture, graphics_exposures, attributes.graphics_exposures); + } + + if (mask & CPSubwindowMode) + { + attributes.subwindow_mode = pPicture -> subWindowMode; + + valuemask |= CPSubwindowMode; + + nxagentSetPictureRemoteValue(pPicture, subwindow_mode, attributes.subwindow_mode); + } + + if (mask & CPClipMask) + { + attributes.clip_mask = None; + + valuemask |= CPClipMask; + + nxagentSetPictureRemoteValue(pPicture, clip_mask, attributes.clip_mask); + } + + if (mask & CPPolyEdge) + { + attributes.poly_edge = pPicture -> polyEdge; + + valuemask |= CPPolyEdge; + + nxagentSetPictureRemoteValue(pPicture, poly_edge, attributes.poly_edge); + } + + if (mask & CPPolyMode) + { + attributes.poly_mode = pPicture -> polyMode; + + valuemask |= CPPolyMode; + + nxagentSetPictureRemoteValue(pPicture, poly_mode, attributes.poly_mode); + } + + if (mask & CPDither) + { + attributes.dither = pPicture -> dither; + + valuemask |= CPDither; + + nxagentSetPictureRemoteValue(pPicture, dither, attributes.dither); + } + + if (mask & CPComponentAlpha) + { + attributes.component_alpha = pPicture -> componentAlpha; + + valuemask |= CPComponentAlpha; + + nxagentSetPictureRemoteValue(pPicture, component_alpha, attributes.component_alpha); + } + + pForm = NULL; + + if (pPicture -> pFormat != NULL) + { + pForm = nxagentMatchingFormats(pPicture -> pFormat); + + #ifdef DEBUG + + nxagentPrintFormat(pForm); + + #endif + } + + if (pForm == NULL) + { + fprintf(stderr, "nxagentCreatePicture: WARNING! The requested format was not found.\n"); + + return 0; + } + + id = XRenderCreatePicture(nxagentDisplay, + nxagentDrawable(pPicture -> pDrawable), + pForm, + valuemask, + &attributes); + + #ifdef TEST + fprintf(stderr, "nxagentCreatePicture: Created picture at [%p] with drawable at [%p].\n", + (void *) pPicture, (void *) pPicture -> pDrawable); + #endif + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif + + nxagentPicturePriv(pPicture) -> picture = id; + + if (nxagentAlphaEnabled == 1 && pPicture -> pDrawable->depth == 32 && + pPicture -> pFormat -> direct.alpha != 0) + { + if (pPicture -> pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentPixmapPriv(nxagentRealPixmap((PixmapPtr) pPicture -> pDrawable)) -> pPicture = pPicture; + } + else if (pPicture -> pDrawable -> type == DRAWABLE_WINDOW) + { + nxagentWindowPriv((WindowPtr) pPicture -> pDrawable) -> pPicture = pPicture; + } + } + + return 1; +} + +XRenderPictFormat *nxagentMatchingFormats(PictFormatPtr pFormat) +{ + int i; + + for (i = 0; i < nxagentNumFormats; i++) + { + if (pFormat -> type == nxagentArrayFormats[i].type && + pFormat -> depth == nxagentArrayFormats[i].depth && + pFormat -> direct.red == nxagentArrayFormats[i].direct.red && + pFormat -> direct.green == nxagentArrayFormats[i].direct.green && + pFormat -> direct.blue == nxagentArrayFormats[i].direct.blue && + pFormat -> direct.redMask == nxagentArrayFormats[i].direct.redMask && + pFormat -> direct.greenMask == nxagentArrayFormats[i].direct.greenMask && + pFormat -> direct.blueMask == nxagentArrayFormats[i].direct.blueMask && + pFormat -> direct.alpha == nxagentArrayFormats[i].direct.alpha && + pFormat -> direct.alphaMask == nxagentArrayFormats[i].direct.alphaMask) + { + return &nxagentArrayFormats[i]; + } + } + + #ifdef DEBUG + fprintf(stderr, "nxagentMatchingFormats: The requested format was not found.\n"); + #endif + + return NULL; +} + +void nxagentDestroyPicture(PicturePtr pPicture) +{ + if (pPicture == NULL || nxagentPicturePriv(pPicture) -> picture == 0) + { + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentDestroyPicture: Going to destroy picture at [%p].\n", + (void *) pPicture); + #endif + + XRenderFreePicture(nxagentDisplay, + nxagentPicturePriv(pPicture) -> picture); + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +int nxagentChangePictureClip(PicturePtr pPicture, int clipType, int nRects, + xRectangle *rects, int xOrigin, int yOrigin) +{ + #ifdef TEST + fprintf(stderr, "nxagentChangePictureClip: Going to change clip of picture at [%p].\n", + (void *) pPicture); + #endif + + #ifdef DEBUG + fprintf(stderr, "nxagentChangePictureClip: clipType [%d] nRects [%d] xRectangle [%p] " + "xOrigin [%d] yOrigin [%d].\n", clipType, nRects, (void *) rects, xOrigin, yOrigin); + #endif + + if (pPicture == NULL) + { + return 0; + } + + switch (clipType) + { + case CT_PIXMAP: + { + #ifdef DEBUG + fprintf(stderr, "nxagentChangePictureClip: Clip type is [CT_PIXMAP].\n"); + #endif + + /* + * if(!nRects) + * { + * return 0; + * } + */ +/* +FIXME: Is this useful or just a waste of bandwidth? + + Apparently useless with QT. +*/ + #ifndef SKIP_LOUSY_RENDER_OPERATIONS + + XRenderSetPictureClipRectangles(nxagentDisplay, + nxagentPicturePriv(pPicture) -> picture, + xOrigin, + yOrigin, + (XRectangle*)rects, + nRects); + + nxagentSetPictureRemoteValue(pPicture, clip_x_origin, xOrigin); + nxagentSetPictureRemoteValue(pPicture, clip_y_origin, yOrigin); + nxagentSetPictureRemoteValue(pPicture, clip_mask, 1); + + #endif + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif + + break; + } + case CT_NONE: + { + #ifdef DEBUG + fprintf(stderr, "nxagentChangePictureClip: Clip type is [CT_NONE].\n"); + #endif +/* +FIXME: Is this useful or just a waste of bandwidth? + + Apparently useless with QT. +*/ + #ifndef SKIP_LOUSY_RENDER_OPERATIONS + + XRenderSetPictureClipRectangles(nxagentDisplay, + nxagentPicturePriv(pPicture) -> picture, + xOrigin, + yOrigin, + (XRectangle*)rects, + nRects); + + nxagentSetPictureRemoteValue(pPicture, clip_x_origin, xOrigin); + nxagentSetPictureRemoteValue(pPicture, clip_y_origin, yOrigin); + nxagentSetPictureRemoteValue(pPicture, clip_mask, 1); + + #endif + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif + + break; + } + case CT_REGION: + { + Region reg; + XRectangle rectangle; + int index; + + #ifdef DEBUG + fprintf(stderr, "nxagentChangePictureClip: Clip type is [CT_REGION].\n"); + #endif + + reg = XCreateRegion(); + + for (index = 0; index <= nRects; index++, rects++) + { + rectangle.x = rects -> x; + rectangle.y = rects -> y; + rectangle.width = rects -> width; + rectangle.height = rects -> height; + + XUnionRectWithRegion(&rectangle, reg, reg); + } +/* +FIXME: Is this useful or just a waste of bandwidth? + + Apparently useless with QT. +*/ + #ifndef SKIP_LOUSY_RENDER_OPERATIONS + + XRenderSetPictureClipRegion(nxagentDisplay, + nxagentPicturePriv(pPicture) -> picture, + reg); + + nxagentSetPictureRemoteValue(pPicture, clip_x_origin, xOrigin); + nxagentSetPictureRemoteValue(pPicture, clip_y_origin, yOrigin); + nxagentSetPictureRemoteValue(pPicture, clip_mask, 1); + + #endif + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif + + XDestroyRegion(reg); + + break; + } + default: + { + #ifdef DEBUG + fprintf(stderr, "nxagentChangePictureClip: clipType not found\n"); + #endif + + break; + } + } + + return 1; +} + +void nxagentDestroyPictureClip(PicturePtr pPicture) +{ + #ifdef DEBUG + fprintf(stderr, "nxagentDestroyPictureClip: Nothing to do.\n"); + #endif +} + +void nxagentChangePicture(PicturePtr pPicture, Mask mask) +{ + XRenderPictureAttributes attributes; + unsigned long valuemask = 0; + + #ifdef DEBUG + fprintf(stderr, "nxagentChangePicture: Going to change picture at [%p] with mask [%ld].\n", + (void *) pPicture, mask); + #endif + + if (pPicture == NULL) + { + return; + } + + if (mask & CPRepeat) + { + attributes.repeat = (Bool)pPicture -> repeat; + + if (nxagentCheckPictureRemoteValue(pPicture, repeat, attributes.repeat) == 0) + { + valuemask |= CPRepeat; + + nxagentSetPictureRemoteValue(pPicture, repeat, attributes.repeat); + } + } + + if (mask & CPAlphaMap) + { + attributes.alpha_map = nxagentPicturePriv(pPicture -> alphaMap) -> picture; + + if (nxagentCheckPictureRemoteValue(pPicture, alpha_map, attributes.alpha_map) == 0) + { + valuemask |= CPAlphaMap; + + nxagentSetPictureRemoteValue(pPicture, alpha_map, attributes.alpha_map); + } + } + + if (mask & CPAlphaXOrigin) + { + attributes.alpha_x_origin = pPicture -> alphaOrigin.x; + + if (nxagentCheckPictureRemoteValue(pPicture, alpha_x_origin, attributes.alpha_x_origin) == 0) + { + valuemask |= CPAlphaXOrigin; + + nxagentSetPictureRemoteValue(pPicture, alpha_x_origin, attributes.alpha_x_origin); + } + } + + if (mask & CPAlphaYOrigin) + { + attributes.alpha_y_origin = pPicture -> alphaOrigin.y; + + if (nxagentCheckPictureRemoteValue(pPicture, alpha_y_origin, attributes.alpha_y_origin) == 0) + { + valuemask |= CPAlphaYOrigin; + + nxagentSetPictureRemoteValue(pPicture, alpha_y_origin, attributes.alpha_y_origin); + } + } + + if (mask & CPClipXOrigin) + { + attributes.clip_x_origin = pPicture -> clipOrigin.x; + + if (nxagentCheckPictureRemoteValue(pPicture, clip_x_origin, attributes.clip_x_origin) == 0) + { + valuemask |= CPClipXOrigin; + + nxagentSetPictureRemoteValue(pPicture, clip_x_origin, attributes.clip_x_origin); + } + } + + if (mask & CPClipYOrigin) + { + attributes.clip_y_origin = pPicture -> clipOrigin.y; + + if (nxagentCheckPictureRemoteValue(pPicture, clip_y_origin, attributes.clip_y_origin) == 0) + { + valuemask |= CPClipYOrigin; + + nxagentSetPictureRemoteValue(pPicture, clip_y_origin, attributes.clip_y_origin); + } + } + + if (mask & CPGraphicsExposure) + { + attributes.graphics_exposures = (Bool)pPicture -> graphicsExposures; + + if (nxagentCheckPictureRemoteValue(pPicture, graphics_exposures, attributes.graphics_exposures) == 0) + { + valuemask |= CPGraphicsExposure; + + nxagentSetPictureRemoteValue(pPicture, graphics_exposures, attributes.graphics_exposures); + } + } + + if (mask & CPSubwindowMode) + { + attributes.subwindow_mode = pPicture -> subWindowMode; + + if (nxagentCheckPictureRemoteValue(pPicture, subwindow_mode, attributes.subwindow_mode) == 0) + { + valuemask |= CPSubwindowMode; + + nxagentSetPictureRemoteValue(pPicture, subwindow_mode, attributes.subwindow_mode); + } + } + + if (mask & CPClipMask) + { + attributes.clip_mask = None; + + /* + * The nxagent doesn't know the remote id of + * the picture's clip mask, so the clip_mask + * value is used as a boolean: it is set to 0 + * when the clip_mask is None, otherwise it is + * 1. + */ + + if (nxagentPicturePriv(pPicture) -> lastServerValues.clip_mask != 0) + { + valuemask |= CPClipMask; + + nxagentSetPictureRemoteValue(pPicture, clip_mask, 0); + } + } + + if (mask & CPPolyEdge) + { + attributes.poly_edge = pPicture -> polyEdge; + + if (nxagentCheckPictureRemoteValue(pPicture, poly_edge, attributes.poly_edge) == 0) + { + valuemask |= CPPolyEdge; + + nxagentSetPictureRemoteValue(pPicture, poly_edge, attributes.poly_edge); + } + } + + if (mask & CPPolyMode) + { + attributes.poly_mode = pPicture -> polyMode; + + if (nxagentCheckPictureRemoteValue(pPicture, poly_mode, attributes.poly_mode) == 0) + { + valuemask |= CPPolyMode; + + nxagentSetPictureRemoteValue(pPicture, poly_mode, attributes.poly_mode); + } + } + + if (mask & CPDither) + { + attributes.dither = pPicture -> dither; + + if (nxagentCheckPictureRemoteValue(pPicture, dither, attributes.dither) == 0) + { + valuemask |= CPDither; + + nxagentSetPictureRemoteValue(pPicture, dither, attributes.dither); + } + } + + if (mask & CPComponentAlpha) + { + attributes.component_alpha = pPicture -> componentAlpha; + + if (nxagentCheckPictureRemoteValue(pPicture, component_alpha, attributes.component_alpha) == 0) + { + valuemask |= CPComponentAlpha; + + nxagentSetPictureRemoteValue(pPicture, component_alpha, attributes.component_alpha); + } + } + + #ifdef TEST + + if (pPicture && pPicture->pDrawable && pPicture -> pDrawable -> type == DRAWABLE_PIXMAP) + { + fprintf(stderr, "nxagentChangePicture: %sPixmap [%p] Picture [%p][%p].\n", + nxagentIsShmPixmap((PixmapPtr)pPicture -> pDrawable) ? "Shared " : "", + (void *) pPicture -> pDrawable, (void *) nxagentPicturePriv(pPicture) -> picture, + (void *) pPicture); + } + + #endif +/* +FIXME: Is this useful or just a waste of bandwidth? + + Apparently useless with QT. + + Without this the text is not rendered on GTK/Cairo. +*/ + #ifndef SKIP_REALLY_ALL_LOUSY_RENDER_OPERATIONS + + if (valuemask != 0) + { + XRenderChangePicture(nxagentDisplay, + nxagentPicturePriv(pPicture) -> picture, + valuemask, + &attributes); + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentChangePicture: Skipping change of picture [%p] on remote X server.\n", + (void *) pPicture); + } + #endif + + #endif + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +void nxagentValidatePicture(PicturePtr pPicture, Mask mask) +{ + #ifdef DEBUG + fprintf(stderr, "nxagentValidatePicture: Nothing to do.\n"); + #endif +} + +void nxagentComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, + INT16 yDst, CARD16 width, CARD16 height) +{ + RegionPtr pDstRegion; + + if (pSrc == NULL || pDst == NULL) + { + return; + } + + #ifdef DEBUG + + if (pSrc && pSrc -> pDrawable != NULL) + { + fprintf(stderr, "nxagentComposite: Source Picture [%lu][%p] with drawable [%s%s][%p].\n", + nxagentPicturePriv(pSrc) -> picture, (void *) pSrc, + (pSrc -> pDrawable -> type == DRAWABLE_PIXMAP && + nxagentIsShmPixmap((PixmapPtr) pSrc -> pDrawable)) ? "Shared " : "", + pSrc -> pDrawable -> type == DRAWABLE_PIXMAP ? "Pixmap" : "Window", + (void *) pSrc -> pDrawable); + } + + if (pDst && pDst->pDrawable) { + fprintf(stderr, "nxagentComposite: Destination Picture [%lu][%p] with drawable [%s%s][%p].\n", + nxagentPicturePriv(pDst) -> picture, (void *) pDst, + (pDst -> pDrawable -> type == DRAWABLE_PIXMAP && + nxagentIsShmPixmap((PixmapPtr) pDst -> pDrawable)) ? "Shared " : "", + pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "Pixmap" : "Window", + (void *) pDst -> pDrawable); + } + + if (pMask && pMask->pDrawable) + { + fprintf(stderr, "nxagentComposite: Mask Picture [%lu][%p] with drawable [%s%s][%p].\n", + nxagentPicturePriv(pMask) -> picture, (void *) pMask, + (pMask -> pDrawable -> type == DRAWABLE_PIXMAP && + nxagentIsShmPixmap((PixmapPtr) pMask -> pDrawable)) ? "Shared " : "", + pMask -> pDrawable -> type == DRAWABLE_PIXMAP ? "Pixmap" : "Window", + (void *) pMask -> pDrawable); + } + + #endif + + if (NXAGENT_SHOULD_DEFER_COMPOSITE(pSrc, pMask, pDst)) + { + pDstRegion = nxagentCreateRegion(pDst -> pDrawable, NULL, xDst, yDst, width, height); + + #ifdef TEST + if ((pDstRegion) && (pDst && pDst->pDrawable)) { + fprintf(stderr, "nxagentComposite: WARNING! Prevented operation on region [%d,%d,%d,%d] " + "for drawable at [%p] with type [%s].\n", pDstRegion -> extents.x1, + pDstRegion -> extents.y1, pDstRegion -> extents.x2, pDstRegion -> extents.y2, + (void *) pDst -> pDrawable, + pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"); + } + #endif + + nxagentMarkCorruptedRegion(pDst -> pDrawable, pDstRegion); + + nxagentFreeRegion(pDst -> pDrawable, pDstRegion); + + return; + } + + /* + * Synchronize the content of the shared memory pixmap + * but pay attention at not doing this more than once. + * We need to wait until the image data has been recom- + * posed at the X server side or the operation will use + * the wrong data. + */ + + if (pSrc -> pDrawable != NULL) + { + nxagentSynchronizeShmPixmap(pSrc -> pDrawable, xSrc, ySrc, width, height); + + if (nxagentDrawableStatus(pSrc -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentComposite: Synchronizing the source drawable [%p].\n", + (void *) pSrc -> pDrawable); + #endif + + nxagentSynchronizeDrawable(pSrc -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + } + } + + if (pDst -> pDrawable != pSrc -> pDrawable) + { + nxagentSynchronizeShmPixmap(pDst -> pDrawable, xDst, yDst, width, height); + + if (nxagentDrawableStatus(pDst -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentComposite: Synchronizing the destination drawable [%p].\n", + (void *) pDst -> pDrawable); + #endif + + nxagentSynchronizeDrawable(pDst -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + } + } + + if (pMask != NULL && pMask -> pDrawable != NULL && + pMask -> pDrawable != pSrc -> pDrawable && + pMask -> pDrawable != pDst -> pDrawable) + { + nxagentSynchronizeShmPixmap(pMask -> pDrawable, xMask, yMask, width, height); + + if (nxagentDrawableStatus(pMask -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentComposite: Synchronizing the mask drawable [%p].\n", + (void *) pMask -> pDrawable); + #endif + + nxagentSynchronizeDrawable(pMask -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + } + } + + /* + * The glyphs flag have to be propagated between + * drawables, in order to avoid to encode the + * text with lossy algorithms (like JPEG). Unlu- + * ckily we have verified that if the render com- + * posite propagates the flag, the deferring of + * render trapezoids doesn't work well. Moreover, + * by commenting out this code we have not noticed + * any visual problems. + * + * if (nxagentDrawableContainGlyphs(pSrc -> pDrawable) == 1) + * { + * nxagentSetDrawableContainGlyphs(pDst -> pDrawable, 1); + * } + */ + + XRenderComposite(nxagentDisplay, + op, + nxagentPicturePriv(pSrc) -> picture, + pMask ? nxagentPicturePriv(pMask) -> picture : 0, + nxagentPicturePriv(pDst) -> picture, + xSrc, + ySrc, + xMask, + yMask, + xDst, + yDst, + width, + height); + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +void nxagentGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists, + XGlyphElt8 *elts, int sizeID, GlyphPtr *glyphsBase) +{ + XRenderPictFormat *pForm; + + BoxRec glyphBox; + + XGlyphElt8 *elements; + + #ifdef SPLIT_GLYPH_LISTS + + GlyphPtr glyph; + + int x; + int y; + int i; + int j; + + #endif /* #ifdef SPLIT_GLYPH_LISTS */ + + if (pSrc == NULL || pDst == NULL) + { + return; + } + + #ifdef TEST + if ((pSrc && pSrc->pDrawable) && (pDst && pDst->pDrawable)) { + fprintf(stderr, "nxagentGlyphs: Called with source [%s][%p] destination [%s][%p] and size id [%d].\n", + (pSrc -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), (void *) pSrc, + (pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), (void *) pDst, + sizeID); + } + #endif + + pForm = NULL; + + if (maskFormat != NULL) + { + pForm = nxagentMatchingFormats(maskFormat); + + #ifdef DEBUG + + nxagentPrintFormat(pForm); + + #endif + + if (pForm == NULL) + { + return; + } + } + + if (nxagentGlyphsExtents != NullBox) + { + glyphBox.x1 = nxagentGlyphsExtents -> x1; + glyphBox.y1 = nxagentGlyphsExtents -> y1; + glyphBox.x2 = nxagentGlyphsExtents -> x2; + glyphBox.y2 = nxagentGlyphsExtents -> y2; + + /* + * By extending the glyph extents the + * visual aspect looks nicer because + * the synchronized region is not glued + * to the fonts. + */ + + if (glyphBox.x2 != glyphBox.x1) + { + glyphBox.x1 -= GLYPH_BOX_MARGIN; + glyphBox.x2 += GLYPH_BOX_MARGIN; + } + + if (glyphBox.y2 != glyphBox.y1) + { + glyphBox.y1 -= GLYPH_BOX_MARGIN; + glyphBox.y2 += GLYPH_BOX_MARGIN; + } + } + + /* + * If the destination window is hidden, the + * operation can be prevented. + */ + + if (pDst -> pDrawable -> type == DRAWABLE_WINDOW) + { + RegionPtr pRegion; + + pRegion = nxagentCreateRegion(pDst -> pDrawable, NULL, glyphBox.x1, glyphBox.y1, + glyphBox.x2 - glyphBox.x1, glyphBox.y2 - glyphBox.y1); + + if (RegionNil(pRegion) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentGlyphs: WARNING! Glyphs prevented on hidden window at [%p].\n", + (void *) pDst -> pDrawable); + #endif + + nxagentFreeRegion(pDst -> pDrawable, pRegion); + + return; + } + + nxagentFreeRegion(pDst -> pDrawable, pRegion); + } + + /* + * Need to synchronize the pixmaps involved in + * the operation before rendering the glyphs + * on the real X server. + */ + + if (pSrc -> pDrawable != NULL && + nxagentDrawableStatus(pSrc -> pDrawable) == NotSynchronized) + { + #ifdef TEST + if (pSrc && pSrc->pDrawable) { + fprintf(stderr, "nxagentGlyphs: Synchronizing source [%s] at [%p].\n", + pSrc -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window", + (void *) pSrc -> pDrawable); + } + #endif + + /* + * If the source drawable is going to be + * repeated over the destination drawable + * during the composite operation, we need + * to synchronize the whole drawable to + * avoid graphical problems. + */ + + if (pSrc -> repeat == 1 || nxagentGlyphsExtents == NullBox) + { + #ifdef DEBUG + if (pSrc && pSrc->pDrawable) { + fprintf(stderr, "nxagentGlyphs: Synchronizing source [%s] at [%p] " + "with geometry [%d,%d,%d,%d].\n", + (pSrc -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), + (void *) pSrc -> pDrawable, pSrc -> pDrawable -> x, pSrc -> pDrawable -> y, + pSrc -> pDrawable -> x + pSrc -> pDrawable -> width, + pSrc -> pDrawable -> y + pSrc -> pDrawable -> height); + } + #endif + + nxagentSynchronizeBox(pSrc -> pDrawable, NullBox, NEVER_BREAK); + } + else + { + #ifdef DEBUG + if (pSrc && pSrc->pDrawable) { + fprintf(stderr, "nxagentGlyphs: Synchronizing region [%d,%d,%d,%d] of source [%s] at [%p] " + "with geometry [%d,%d,%d,%d].\n", glyphBox.x1, glyphBox.y1, glyphBox.x2, glyphBox.y2, + (pSrc -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), + (void *) pSrc -> pDrawable, pSrc -> pDrawable -> x, pSrc -> pDrawable -> y, + pSrc -> pDrawable -> x + pSrc -> pDrawable -> width, + pSrc -> pDrawable -> y + pSrc -> pDrawable -> height); + } + #endif + + nxagentSynchronizeBox(pSrc -> pDrawable, &glyphBox, NEVER_BREAK); + } + + if (pSrc -> pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentIncreasePixmapUsageCounter((PixmapPtr) pSrc -> pDrawable); + } + } + + if (pSrc -> pDrawable != pDst -> pDrawable && + nxagentDrawableStatus(pDst -> pDrawable) == NotSynchronized) + { + #ifdef TEST + if (pDst && pDst->pDrawable) { + fprintf(stderr, "nxagentGlyphs: Synchronizing destination [%s] at [%p].\n", + pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window", + (void *) pDst -> pDrawable); + } + #endif + + if (nxagentGlyphsExtents == NullBox) + { + #ifdef DEBUG + if (pDst && pDst->pDrawable) { + fprintf(stderr, "nxagentGlyphs: Synchronizing destination [%s] at [%p] " + "with geometry [%d,%d,%d,%d].\n", + (pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), + (void *) pDst -> pDrawable, pDst -> pDrawable -> x, pDst -> pDrawable -> y, + pDst -> pDrawable -> x + pDst -> pDrawable -> width, + pDst -> pDrawable -> y + pDst -> pDrawable -> height); + } + #endif + + nxagentSynchronizeBox(pDst -> pDrawable, NullBox, NEVER_BREAK); + } + else + { + #ifdef DEBUG + if (pDst && pDst->pDrawable) { + fprintf(stderr, "nxagentGlyphs: Synchronizing region [%d,%d,%d,%d] of destination [%s] at [%p] " + "with geometry [%d,%d,%d,%d].\n", glyphBox.x1, glyphBox.y1, glyphBox.x2, glyphBox.y2, + (pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), + (void *) pDst -> pDrawable, pDst -> pDrawable -> x, pDst -> pDrawable -> y, + pDst -> pDrawable -> x + pDst -> pDrawable -> width, + pDst -> pDrawable -> y + pDst -> pDrawable -> height); + } + #endif + + nxagentSynchronizeBox(pDst -> pDrawable, &glyphBox, NEVER_BREAK); + } + + if (pDst -> pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentIncreasePixmapUsageCounter((PixmapPtr) pDst -> pDrawable); + } + } + + nxagentSetDrawableContainGlyphs(pDst -> pDrawable, 1); + + #ifdef TEST + if (pDst && pDst->pDrawable) { + fprintf(stderr, "nxagentGlyphs: Glyph flag set on drawable [%s][%p].\n", + pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window", + (void *) pDst -> pDrawable); + } + #endif + + #ifdef SPLIT_GLYPH_LISTS + + /* + * We split glyphs lists here and recalculate + * the offsets of each list to make them ab- + * solute and not relatives to the prior list. + * This way each time we call XRenderComposi- + * teText it has to deal only with a list of + * glyphs. This is done to further improve + * caching. + */ + + elements = elts; + + if (nlists > 1) + { + for (j = 1; j < nlists; j++) + { + x = elements -> xOff; + y = elements -> yOff; + + #ifdef TEST + fprintf(stderr, "nxagentGlyphs: Element [%d] of [%d] has offset [%d,%d].\n", + j, nlists, elements -> xOff, elements -> yOff); + #endif + + for (i = 0; i < elements -> nchars; i++) + { + glyph = *glyphsBase++; + + x += glyph -> info.xOff; + y += glyph -> info.yOff; + + #ifdef TEST + fprintf(stderr, "nxagentGlyphs: Glyph at index [%d] has offset [%d,%d] and " + "position [%d,%d].\n", i, elements -> nchars, glyph -> info.xOff, + glyph -> info.yOff, x, y); + #endif + } + + elements++; + + elements -> xOff += x; + elements -> yOff += y; + + #ifdef TEST + fprintf(stderr, "nxagentGlyphs: New offset for list at [%p] is [%d,%d].\n", + elements, elements -> xOff, elements -> yOff); + #endif + } + + elements = elts; + } + + switch (sizeID) + { + case 1: + { + for (j = 0; j < nlists; j++) + { + XRenderCompositeText8(nxagentDisplay, + op, + nxagentPicturePriv(pSrc)->picture, + nxagentPicturePriv(pDst)->picture, + pForm, + xSrc, + ySrc, + elements -> xOff, + elements -> yOff, + (XGlyphElt8*) elements, + 1); + + elements++; + } + + break; + } + case 2: + { + for (j = 0; j < nlists; j++) + { + XRenderCompositeText16(nxagentDisplay, + op, + nxagentPicturePriv(pSrc) -> picture, + nxagentPicturePriv(pDst) -> picture, + pForm, + xSrc, + ySrc, + elements -> xOff, + elements -> yOff, + (XGlyphElt16*) elements, + 1); + + elements++; + } + + break; + } + case 4: + { + for (j = 0; j < nlists; j++) + { + XRenderCompositeText32(nxagentDisplay, + op, + nxagentPicturePriv(pSrc) -> picture, + nxagentPicturePriv(pDst) -> picture, + pForm, + xSrc, + ySrc, + elements -> xOff, + elements -> yOff, + (XGlyphElt32*) elements, + 1); + + elements++; + } + + break; + } + default: + { + #ifdef WARNING + fprintf(stderr, "nxagentGlyphs: WARNING! Invalid size id [%d].\n", + sizeID); + #endif + + break; + } + } + + #else /* #ifdef SPLIT_GLYPH_LISTS */ + + elements = elts; + + switch (sizeID) + { + case 1: + { + XRenderCompositeText8(nxagentDisplay, + op, + nxagentPicturePriv(pSrc)->picture, + nxagentPicturePriv(pDst)->picture, + pForm, + xSrc, + ySrc, + elements -> xOff, + elements -> yOff, + (XGlyphElt8*) elements, + nlists); + + break; + } + case 2: + { + XRenderCompositeText16(nxagentDisplay, + op, + nxagentPicturePriv(pSrc) -> picture, + nxagentPicturePriv(pDst) -> picture, + pForm, + xSrc, + ySrc, + elements -> xOff, + elements -> yOff, + (XGlyphElt16*) elements, + nlists); + + break; + } + case 4: + { + XRenderCompositeText32(nxagentDisplay, + op, + nxagentPicturePriv(pSrc) -> picture, + nxagentPicturePriv(pDst) -> picture, + pForm, + xSrc, + ySrc, + elements -> xOff, + elements -> yOff, + (XGlyphElt32*) elements, + nlists); + + break; + } + default: + { + #ifdef WARNING + fprintf(stderr, "nxagentGlyphs: WARNING! Invalid size id [%d].\n", + sizeID); + #endif + + break; + } + } + + #endif /* #ifdef SPLIT_GLYPH_LISTS */ +} + +void nxagentCompositeRects(CARD8 op, PicturePtr pDst, xRenderColor *color, + int nRect, xRectangle *rects) +{ + RegionPtr rectRegion; + + if (pDst == NULL) + { + return; + } + + #ifdef TEST + if (pDst && pDst->pDrawable) { + fprintf(stderr, "nxagentCompositeRects: Called for picture at [%p] with [%s] at [%p].\n", + (void *) pDst, (pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), + (void *) pDst -> pDrawable); + } + #endif + + /* + * The CompositeRects() clears the destination's + * corrupted region like the PolyFillRects() does. + * As this case is harder to handle, at the moment + * we only check for two ops. + */ + + if (nxagentDrawableStatus(pDst -> pDrawable) == NotSynchronized && + (op == PictOpSrc || + (op == PictOpOver && color -> alpha == 0xffff))) + { + rectRegion = RegionFromRects(nRect, rects, CT_REGION); + + if (pDst -> clientClipType != CT_NONE) + { + RegionRec tmpRegion; + + RegionInit(&tmpRegion, NullBox, 1); + + RegionCopy(&tmpRegion, (RegionPtr) pDst -> clientClip); + + if (pDst -> clipOrigin.x != 0 || pDst -> clipOrigin.y != 0) + { + RegionTranslate(&tmpRegion, pDst -> clipOrigin.x, pDst -> clipOrigin.y); + } + + RegionIntersect(rectRegion, rectRegion, &tmpRegion); + + RegionUninit(&tmpRegion); + } + + #ifdef TEST + fprintf(stderr, "nxagentCompositeRects: Going to clean the drawable with extents [%d,%d,%d,%d].\n", + rectRegion -> extents.x1, rectRegion -> extents.y1, rectRegion -> extents.x2, rectRegion -> extents.y2); + #endif + + nxagentUnmarkCorruptedRegion(pDst -> pDrawable, rectRegion); + + RegionDestroy(rectRegion); + } + + XRenderFillRectangles(nxagentDisplay, + op, + (Picture)nxagentPicturePriv(pDst) -> picture, + (XRenderColor *) color, + (XRectangle *) rects, + nRect); + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +void nxagentTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps) +{ + XRenderPictFormat *pForm; + + XTrapezoid *current = (XTrapezoid *) traps; + + RegionPtr pDstRegion; + + int remaining = ntrap; + + #ifdef TEST + fprintf(stderr, "nxagentTrapezoids: Source [%p] destination [%p] coordinates " + "[%d,%d] elements [%d].\n", (void *) pSrc, (void *) pDst, + xSrc, ySrc, ntrap); + #endif + + if (pSrc == NULL || pDst == NULL) + { + return; + } + + pForm = NULL; + + if (maskFormat != NULL) + { + pForm = nxagentMatchingFormats(maskFormat); + + #ifdef DEBUG + + nxagentPrintFormat(pForm); + + #endif + + if (pForm == NULL) + { + return; + } + } +/* +FIXME: Is this useful or just a waste of bandwidth? + + Apparently useless with QT. +*/ + #ifndef SKIP_LOUSY_RENDER_OPERATIONS + + #ifdef TEST + + if (pSrc->pDrawable) { + fprintf(stderr, "nxagentTrapezoids: Source is a [%s] of geometry [%d,%d].\n", + (pSrc -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), + pSrc -> pDrawable -> width, pSrc -> pDrawable -> height); + } + if (pSrc ->pDrawable != pDst -> pDrawable) + { + fprintf(stderr, "nxagentTrapezoids: Destination is a [%s] of geometry [%d,%d].\n", + (pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window"), + pDst -> pDrawable -> width, pDst -> pDrawable -> height); + } + + #endif + + /* + * If the destination drawable is not synchronized + * but the trapezoids extents are included in the + * dirty region, we can defer the operation. + */ + + if (nxagentDrawableStatus(pDst -> pDrawable) == NotSynchronized && + RegionContainsRect(nxagentCorruptedRegion(pDst -> pDrawable), + nxagentTrapezoidExtents) == rgnIN) + { + #ifdef TEST + if (pDst && pDst->pDrawable) { + fprintf(stderr, "nxagentTrapezoids: WARNING! Prevented operation on region [%d,%d,%d,%d] already dirty " + "for drawable [%s][%p].\n", nxagentTrapezoidExtents -> x1, nxagentTrapezoidExtents -> y1, + nxagentTrapezoidExtents -> x2, nxagentTrapezoidExtents -> y2, + pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window", + (void *) pDst -> pDrawable); + } + #endif + + if (pDst -> pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentPixmapContainTrapezoids((PixmapPtr) pDst -> pDrawable) = 1; + } + + return; + } + + /* + * If the destination doesn't contain any glyphs, + * we can defer the trapezoids drawing by marking + * the destination as dirty. + */ + + if (NXAGENT_SHOULD_DEFER_TRAPEZOIDS(pDst -> pDrawable)) + { + pDstRegion = nxagentCreateRegion(pDst -> pDrawable, NULL, + nxagentTrapezoidExtents -> x1, + nxagentTrapezoidExtents -> y1, + nxagentTrapezoidExtents -> x2 - nxagentTrapezoidExtents -> x1, + nxagentTrapezoidExtents -> y2 - nxagentTrapezoidExtents -> y1); + + #ifdef TEST + if (pDst && pDst->pDrawable) { + fprintf(stderr, "nxagentTrapezoids: WARNING! Prevented operation on region [%d,%d,%d,%d] " + "for drawable [%s][%p].\n", pDstRegion -> extents.x1, pDstRegion -> extents.y1, + pDstRegion -> extents.x2, pDstRegion -> extents.y2, + pDst -> pDrawable -> type == DRAWABLE_PIXMAP ? "pixmap" : "window", + (void *) pDst -> pDrawable); + } + #endif + + nxagentMarkCorruptedRegion(pDst -> pDrawable, pDstRegion); + + nxagentFreeRegion(pDst -> pDrawable, pDstRegion); + + if (pDst -> pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentPixmapContainTrapezoids((PixmapPtr) pDst -> pDrawable) = 1; + } + + return; + } + + if (pSrc -> pDrawable != NULL && + nxagentDrawableStatus(pSrc -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentTrapezoids: Going to synchronize the source drawable at [%p].\n", + (void *) pSrc -> pDrawable); + #endif + + nxagentSynchronizeBox(pSrc -> pDrawable, NullBox, NEVER_BREAK); + } + + if (nxagentDrawableStatus(pDst -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentTrapezoids: Going to synchronize the destination drawable at [%p].\n", + (void *) pDst -> pDrawable); + #endif + + nxagentSynchronizeBox(pDst -> pDrawable, nxagentTrapezoidExtents, NEVER_BREAK); + } + + while (remaining > 0) + { + XRenderCompositeTrapezoids(nxagentDisplay, + op, + nxagentPicturePriv(pSrc) -> picture, + nxagentPicturePriv(pDst) -> picture, + pForm, + xSrc, + ySrc, + (XTrapezoid *) current, + (remaining > TRAPEZOIDS_PER_REQUEST ? + TRAPEZOIDS_PER_REQUEST : remaining)); + + remaining -= TRAPEZOIDS_PER_REQUEST; + current += TRAPEZOIDS_PER_REQUEST; + } + + #endif + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +void nxagentRasterizeTrapezoid(PicturePtr pMask, xTrapezoid *trap, + int x_off, int y_off) +{ + #ifdef DEBUG + fprintf(stderr, "nxagentRasterizeTrapezoids: Nothing to do.\n"); + #endif +} + +void nxagentTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tris) +{ + XRenderPictFormat *pForm; + + #ifdef DEBUG + fprintf(stderr, "nxagentTriangles: Source [%p] Destination [%p] Coordinates [%d,%d] Elements [%d].\n", + (void *) pSrc, (void *) pDst, xSrc, ySrc, ntri); + #endif + + if (pSrc == NULL || pDst == NULL) + { + return; + } + + pForm = NULL; + + if (maskFormat != NULL) + { + pForm = nxagentMatchingFormats(maskFormat); + + #ifdef DEBUG + + nxagentPrintFormat(pForm); + + #endif + + if (pForm == NULL) + { + return; + } + } + + /* + * If the X_RenderCompositeTriangles requests + * increment the traffic, we can defer the + * operation like nxagentTrapezoids() does. + */ + + if (pSrc -> pDrawable != NULL && + nxagentDrawableStatus(pSrc -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentTriangles: Going to synchronize the source drawable at [%p].\n", + (void *) pSrc -> pDrawable); + #endif + + nxagentSynchronizeDrawable(pSrc -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + } + + if (nxagentDrawableStatus(pDst -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentTriangles: Going to synchronize the destination drawable at [%p].\n", + (void *) pDst -> pDrawable); + #endif + + nxagentSynchronizeDrawable(pDst -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + } + + XRenderCompositeTriangles(nxagentDisplay, + op, + nxagentPicturePriv(pSrc) -> picture, + nxagentPicturePriv(pDst) -> picture, + pForm, + xSrc, + ySrc, + (XTriangle*)tris, + ntri); + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +void nxagentTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int npoint, xPointFixed *points) +{ + XRenderPictFormat *pForm; + + #ifdef DEBUG + fprintf(stderr, "nxagentTriStrip: Source [%p] Destination [%p] Coordinates [%d,%d] Elements [%d].\n", + (void *) pSrc, (void *) pDst, xSrc, ySrc, npoint); + #endif + + if (pSrc == NULL || pDst == NULL) + { + return; + } + + pForm = NULL; + + if (maskFormat != NULL) + { + pForm = nxagentMatchingFormats(maskFormat); + + #ifdef DEBUG + + nxagentPrintFormat(pForm); + + #endif + + if (pForm == NULL) + { + return; + } + } + + /* + * If the X_RenderCompositeTriStrip requests + * increment the traffic, we can defer the + * operation like nxagentTrapezoids() does. + */ + + if (pSrc -> pDrawable != NULL && + nxagentDrawableStatus(pSrc -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentTriStrip: Going to synchronize the source drawable at [%p].\n", + (void *) pSrc -> pDrawable); + #endif + + nxagentSynchronizeDrawable(pSrc -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + } + + if (nxagentDrawableStatus(pDst -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentTriStrip: Going to synchronize the destination drawable at [%p].\n", + (void *) pDst -> pDrawable); + #endif + + nxagentSynchronizeDrawable(pDst -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + } + + XRenderCompositeTriStrip(nxagentDisplay, + op, + nxagentPicturePriv(pSrc) -> picture, + nxagentPicturePriv(pDst) -> picture, + pForm, + xSrc, + ySrc, + (XPointFixed*)points, + npoint); + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +void nxagentTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int npoint, xPointFixed *points) +{ + XRenderPictFormat *pForm; + + #ifdef DEBUG + fprintf(stderr, "nxagentTriFan: Source [%p] Destination [%p] Coordinates [%d,%d] Elements [%d].\n", + (void *) pSrc, (void *) pDst, xSrc, ySrc, npoint); + #endif + + if (pSrc == NULL || pDst == NULL) + { + return; + } + + pForm = NULL; + + if (maskFormat != NULL) + { + pForm = nxagentMatchingFormats(maskFormat); + + #ifdef DEBUG + + nxagentPrintFormat(pForm); + + #endif + + if (pForm == NULL) + { + return; + } + } + + /* + * If the X_RenderCompositeTriFan requests + * increment the traffic, we can defer the + * operation like nxagentTrapezoids() does. + */ + + if (pSrc -> pDrawable != NULL && + nxagentDrawableStatus(pSrc -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentTriFan: Going to synchronize the source drawable at [%p].\n", + (void *) pSrc -> pDrawable); + #endif + + nxagentSynchronizeDrawable(pSrc -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + } + + if (nxagentDrawableStatus(pDst -> pDrawable) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentTriFan: Going to synchronize the destination drawable at [%p].\n", + (void *) pDst -> pDrawable); + #endif + + nxagentSynchronizeDrawable(pDst -> pDrawable, DO_WAIT, NEVER_BREAK, NULL); + } + + XRenderCompositeTriFan(nxagentDisplay, + op, + nxagentPicturePriv(pSrc) -> picture, + nxagentPicturePriv(pDst) -> picture, + pForm, + xSrc, + ySrc, + (XPointFixed*)points, + npoint); + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +void nxagentQueryFormats() +{ + XRenderInfo *xri; + XExtDisplayInfo *info = NULL; + XRenderPictFormat *pformat=NULL; + + int i; + + #ifdef DEBUG + fprintf(stderr, "nxagentQueryFormats.\n"); + #endif + + if (XRenderQueryFormats(nxagentDisplay)) + { + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif + + info = (XExtDisplayInfo *) XRenderFindDisplay(nxagentDisplay); + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif + + xri = (XRenderInfo *) info -> data; + + pformat = xri -> format; + + for (i = 0; i < xri -> nformat; i++) + { + nxagentArrayFormats[i] = *pformat; + + #ifdef DEBUG + fprintf(stderr, "nxagentQueryFormats: Added format type [%d] depth [%d] rgb [%d,%d,%d] " + "mask rgb [%d,%d,%d] alpha [%d] alpha mask [%d].\n", + nxagentArrayFormats[i].type, nxagentArrayFormats[i].depth, nxagentArrayFormats[i].direct.red, + nxagentArrayFormats[i].direct.green, nxagentArrayFormats[i].direct.blue, + nxagentArrayFormats[i].direct.redMask, nxagentArrayFormats[i].direct.greenMask, + nxagentArrayFormats[i].direct.blueMask, nxagentArrayFormats[i].direct.alpha, + nxagentArrayFormats[i].direct.alphaMask); + #endif + + pformat++; + } + + #ifdef DEBUG + + if (nxagentNumFormats == 0) + { + fprintf(stderr, "nxagentQueryFormats: Number of formats is [%d].\n", + i); + } + else + { + fprintf(stderr, "nxagentQueryFormats: Old number of formats is [%d]. New number of formats is [%d].\n", + nxagentNumFormats, i); + } + + #endif + + nxagentNumFormats = i; + } +} + +void nxagentCreateGlyphSet(GlyphSetPtr pGly) +{ + XRenderPictFormat *pForm; + + #ifdef DEBUG + fprintf(stderr, "nxagentCreateGlyphSet: Glyphset at [%p].\n", (void *) pGly); + #endif + + pForm = NULL; + + if (pGly -> format != NULL) + { + pForm = nxagentMatchingFormats(pGly -> format); + + #ifdef DEBUG + + nxagentPrintFormat(pForm); + + #endif + + if (pForm == NULL) + { + return; + } + } + + pGly -> remoteID = XRenderCreateGlyphSet(nxagentDisplay, pForm); + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +void nxagentReferenceGlyphSet(GlyphSetPtr glyphSet) +{ + if (glyphSet -> remoteID == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentReferenceGlyphSet: Operation deferred because glyphset at [%p] is corrupted.\n", + (void *) glyphSet); + #endif + + return; + } + + XRenderReferenceGlyphSet (nxagentDisplay, glyphSet -> remoteID); +} + +void nxagentFreeGlyphSet(GlyphSetPtr glyphSet) +{ + if (glyphSet -> remoteID == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentFreeGlyphs: Operation ignored because glyphset at [%p] is corrupted.\n", + (void *) glyphSet); + #endif + + return; + } + + XRenderFreeGlyphSet(nxagentDisplay, glyphSet -> remoteID); +} + +void nxagentAddGlyphs(GlyphSetPtr glyphSet, Glyph *gids, xGlyphInfo *gi, + int nglyphs, CARD8 *images, int sizeImages) +{ + GlyphRefPtr gr; + Glyph *tempGids; + + int i; + + CARD8 *normalizedImages; + + #ifdef DEBUG + fprintf(stderr, "nxagentAddGlyphs: Glyphset at [%p]. Number of glyphs [%d].\n", + (void *) glyphSet, nglyphs); + #endif + + if (glyphSet -> remoteID == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentAddGlyphs: Going to reconnect the glyhpset at [%p] before adding glyphs.\n", + (void *) glyphSet); + #endif + + nxagentReconnectGlyphSet(glyphSet, (XID) 0, (void*) NULL); + } + + /* + * By adding a glyph to a glyphset on + * remote X server we mark its reference + * as synchronized. + */ + + tempGids = gids; + + for (i = 0; i < nglyphs; i++) + { + if ((gr = FindGlyphRef(&glyphSet -> hash, *tempGids, 0, 0)) && + gr -> glyph != DeletedGlyph) + { + #ifdef DEBUG + fprintf(stderr, "nxagentAddGlyphs: Added Glyph [%p][%ld] to glyphset [%p].\n", + (void *) gr -> glyph, *tempGids, (void *) glyphSet); + #endif + + gr -> corruptedGlyph = 0; + } + + tempGids++; + } + + normalizedImages = NULL; + + if (sizeImages > 0) + { + normalizedImages = malloc(sizeImages); + + if (normalizedImages != NULL) + { + memcpy(normalizedImages, images, sizeImages); + + if (glyphDepths[glyphSet -> fdepth] == 1 && + nxagentServerOrder() != BitmapBitOrder(nxagentDisplay)) + { + nxagentBitOrderInvert ((unsigned char *) normalizedImages, sizeImages); + } + } + else + { + #ifdef PANIC + fprintf(stderr, "nxagentAddGlyphs: PANIC! Allocation of normalized glyph images failed.\n"); + #endif + } + } + + if (normalizedImages == NULL) + { + normalizedImages = images; + } + + XRenderAddGlyphs(nxagentDisplay, + glyphSet -> remoteID, + gids, + (XGlyphInfo*)(gi), + nglyphs, + (char*) normalizedImages, + sizeImages); + + if (normalizedImages != images) + { + free(normalizedImages); + } + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif +} + +void nxagentFreeGlyphs(GlyphSetPtr glyphSet, CARD32 *gids, int nglyph) +{ + GlyphRefPtr gr; + CARD32 *tempGids; + Glyph gid; + + int i; + + if (glyphSet -> remoteID == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentFreeGlyphs: Operation ignored because glyphset at [%p] is corrupted.\n", + (void *) glyphSet); + #endif + + return; + } + + /* + * We loop across the list of glyphs id + * to establish if they have been added + * to glyphset on remote X server, so + * they can be freed. + */ + + tempGids = gids; + + for (i = 0; i < nglyph; i++) + { + gid = (Glyph)*tempGids; + + if ((gr = FindGlyphRef(&glyphSet -> hash, *tempGids, 0, 0)) && + gr -> glyph != DeletedGlyph && + gr -> corruptedGlyph == 0) + { + XRenderFreeGlyphs(nxagentDisplay, glyphSet -> remoteID, &gid, 1); + } + + tempGids++; + } +} + +void nxagentSetPictureTransform(PicturePtr pPicture, void * transform) +{ + #ifdef TEST + fprintf(stderr, "nxagentSetPictureTransform: Going to set transform [%p] to picture at [%p].\n", + (void *) transform, (void *) pPicture); + #endif + +/* +FIXME: Is this useful or just a waste of bandwidth? + + Apparently useless with QT. +*/ + #ifndef SKIP_LOUSY_RENDER_OPERATIONS + + XRenderSetPictureTransform(nxagentDisplay, + nxagentPicturePriv(pPicture) -> picture, + (XTransform *) transform); + #endif +} + +void nxagentSetPictureFilter(PicturePtr pPicture, char *filter, int name_size, + void * params, int nparams) +{ + char *szFilter = Xmalloc(name_size + 1); + + if (szFilter == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentSetPictureFilter: error allocating memory for filter name.\n"); + #endif + + return; + } + + strncpy(szFilter, filter, name_size); + + szFilter[name_size] = 0; + + #ifdef TEST + fprintf(stderr, "nxagentSetPictureFilter: Going to set filter [%s] to picture at [%p].\n", + szFilter, (void *) pPicture); + #endif +/* +FIXME: Is this useful or just a waste of bandwidth? + + Apparently useless with QT. +*/ + #ifndef SKIP_LOUSY_RENDER_OPERATIONS + + XRenderSetPictureFilter(nxagentDisplay, + nxagentPicturePriv(pPicture) -> picture, + szFilter, + (XFixed *) params, + nparams); + #endif + + free(szFilter); +} + + +Bool nxagentPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats) +{ + #ifdef RENDER + + #ifdef DEBUG + fprintf(stderr, "nxagentPictureInit: Screen [%p].\n", (void *) pScreen); + #endif + + nxagentQueryFormats(); + + if (fbPictureInit(pScreen, formats, nformats) == 0) + { + return FALSE; + } + + nxagentPicturePrivateIndex = AllocatePicturePrivateIndex(); + + AllocatePicturePrivate(pScreen, nxagentPicturePrivateIndex, sizeof(nxagentPrivPictureRec)); + + #endif + + return TRUE; +} + +#ifdef DEBUG + +static void nxagentPrintFormat(XRenderPictFormat *pFormat) +{ + if (pFormat == NULL) + { + fprintf(stderr, "nxagentPrintFormat: WARNING! null pointer passed to function.\n"); + + return; + } + + fprintf(stderr, "nxagentPrintFormat: Dumping information for format at [%p]:\n\ + type=%d\n\ + depth=%d\n\ + red=%d\n\ + redMask=%d\n\ + green=%d\n\ + greenMask=%d\n\ + blue=%d\n\ + blueMask=%d\n\ + alpha=%d\n\ + alphaMask=%d\n", + (void *) pFormat, + pFormat -> type, + pFormat -> depth, + pFormat -> direct.red, + pFormat -> direct.redMask, + pFormat -> direct.green, + pFormat -> direct.greenMask, + pFormat -> direct.blue, + pFormat -> direct.blueMask, + pFormat -> direct.alpha, + pFormat -> direct.alphaMask); +} + +#endif + +Bool nxagentFillGlyphSet(GlyphSetPtr pGly) +{ + GlyphPtr glyph; + + int i; + + #ifdef DEBUG + fprintf(stderr, "nxagentFillGlyphSet: GlyphSet at [%p] Refcount [%ld] Glyphs [%ld] " + "Format [%p] FDepth [%d] RemoteID [%ld].\n", (void *) pGly, pGly -> refcnt, + pGly -> hash.hashSet -> size, (void *) pGly -> format, pGly -> fdepth, pGly -> remoteID); + #endif + + /* + * The glyphs are synchronized when they + * are used in a composite text. During + * the reconnection we have only to mark + * corrupted the glyphs for each glyphset. + */ + + for (i = 0; i < pGly -> hash.hashSet -> size; i++) + { + glyph = pGly -> hash.table[i].glyph; + + if (glyph && (glyph != DeletedGlyph)) + { + pGly -> hash.table[i].corruptedGlyph = 1; + } + } + + return TRUE; +} + +void nxagentReconnectGlyphSet(void* p0, XID x1, void *p2) +{ + GlyphSetPtr pGly = (GlyphSetPtr) p0; + + XRenderPictFormat *pForm = NULL; + + int i; + + if (nxagentReconnectTrap == 0) + { + #ifdef DEBUG + fprintf(stderr, "nxagentReconnectGlyphSet: GlyphSet at [%p].\n", (void *) pGly); + #endif + + if (pGly -> format) + { + pForm = nxagentMatchingFormats(pGly -> format); + } + + pGly -> remoteID = XRenderCreateGlyphSet(nxagentDisplay, pForm); + + /* + * If we have deferred the operation, we + * have to check the number of references + * to the glyphset to update the X server. + */ + + if ((i = pGly -> refcnt) > 1) + { + while (i-- > 1) + { + nxagentReferenceGlyphSet(pGly); + } + } + + #ifdef DEBUG + + XSync(nxagentDisplay, 0); + + #endif + + nxagentFillGlyphSet(pGly); + } + else + { + pGly -> remoteID = 0; + } +} + +Bool nxagentReconnectAllGlyphSet(void *p) +{ + Bool success = TRUE; + int i; + + nxagentQueryFormats(); + + #ifdef DEBUG + fprintf(stderr, "nxagentReconnectAllGlyphSet\n"); + #endif + + for (i = 0; (i < MAXCLIENTS) && (success); i++) + { + if (clients[i]) + { + FindClientResourcesByType(clients[i], GlyphSetType, nxagentReconnectGlyphSet, &success); + } + } + + return success; +} + +void nxagentReconnectPicture(void * p0, XID x1, void *p2) +{ + PicturePtr pPicture = (PicturePtr) p0; + Bool *pBool = (Bool *) p2; + unsigned long mask = 0; + + XRenderPictureAttributes attributes; + XRenderPictFormat *pForm; + + #ifdef TEST + fprintf(stderr, "nxagentReconnectPicture: Called with bool [%d] and picture at [%p].\n", + *pBool, (void *) pPicture); + + fprintf(stderr, "nxagentReconnectPicture: Virtual picture is [%ld].\n", + nxagentPicture(pPicture)); + #endif + + /* + * Check if a previous operation has failed + * and that the involved objects are valid. + */ + + if (*pBool == 0 || pPicture == NULL || + nxagentPicture(pPicture) != 0) + { + return; + } + + if (pPicture -> repeat) + { + mask |= CPRepeat; + + attributes.repeat = (Bool) pPicture -> repeat; + } + + if (pPicture -> alphaMap) + { + if (!nxagentPicture(pPicture -> alphaMap)) + { + nxagentReconnectPicture(pPicture -> alphaMap, 0, pBool); + + if (!*pBool || !nxagentPicture(pPicture -> alphaMap)) + { + return; + } + } + + attributes.alpha_map = nxagentPicture(pPicture -> alphaMap); + attributes.alpha_x_origin = pPicture -> alphaOrigin.x; + attributes.alpha_y_origin = pPicture -> alphaOrigin.y; + + mask |= (CPAlphaMap | CPAlphaXOrigin | CPAlphaYOrigin); + } + + if (pPicture -> graphicsExposures) + { + attributes.graphics_exposures = pPicture -> graphicsExposures; + + mask |= CPGraphicsExposure; + } + + attributes.subwindow_mode = pPicture -> subWindowMode; + + mask |= CPSubwindowMode; + + attributes.poly_edge = pPicture -> polyEdge; + + mask |= CPPolyEdge; + + attributes.poly_mode = pPicture -> polyMode; + + mask |= CPPolyMode; + + attributes.dither = pPicture -> dither; + + mask |= CPDither; + + attributes.component_alpha = pPicture -> componentAlpha; + + mask |= CPComponentAlpha; + + pForm = NULL; + + if (pPicture -> pFormat) + { + pForm = nxagentMatchingFormats(pPicture -> pFormat); + + #ifdef DEBUG + + nxagentPrintFormat(pForm); + + #endif + } + + if (!pForm && pPicture->pSourcePict) + { + /*possible we need to add support for other picture types, for example gradients...*/ + switch(pPicture->pSourcePict->type) + { + case SourcePictTypeSolidFill: + nxagentPicturePriv(pPicture) -> picture = XRenderCreateSolidFill(nxagentDisplay, + (const XRenderColor*) &pPicture->pSourcePict->solidFill.fullColor); + break; + } + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentReconnectPicture: Creating picture at [%p] with drawable [%ld] at [%p].\n", + (void *) pPicture, nxagentDrawable(pPicture -> pDrawable), (void *) pPicture -> pDrawable); + + fprintf(stderr, "nxagentReconnectPicture: Format is at [%p] mask is [%ld] attributes are at [%p].\n", + (void *) pForm, mask, (void *) &attributes); + #endif + + nxagentPicture(pPicture) = XRenderCreatePicture(nxagentDisplay, + nxagentDrawable(pPicture -> pDrawable), + pForm, + mask, + &attributes); + + #ifdef TEST + + XSync(nxagentDisplay, 0); + + #endif + + #ifdef TEST + fprintf(stderr, "nxagentReconnectPicture: Reconnected picture at [%p] with value [%ld].\n", + (void *) pPicture, nxagentPicture(pPicture)); + #endif + + if (nxagentAlphaEnabled == 1 && pPicture -> pDrawable -> depth == 32 && + pPicture -> pFormat -> direct.alpha != 0) + { + if (pPicture -> pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentPixmapPriv((PixmapPtr) pPicture -> pDrawable) -> pPicture = pPicture; + } + else if (pPicture -> pDrawable -> type == DRAWABLE_WINDOW) + { + nxagentWindowPriv((WindowPtr) pPicture -> pDrawable) -> pPicture = pPicture; + } + } +} + +Bool nxagentReconnectAllPicture(void *p) +{ + int i; + Bool r; + + #ifdef TEST + fprintf(stderr, "nxagentReconnectAllPicture: Going to recreate all pictures.\n"); + #endif + + for (i = 0, r = 1; i < MAXCLIENTS; i++) + { + if (clients[i]) + { + FindClientResourcesByType(clients[i], PictureType, nxagentReconnectPicture, &r); + + #ifdef WARNING + + if (r == False) + { + fprintf(stderr, "nxagentReconnectAllPicture: WARNING! Failed to recreate " + "picture for client [%d].\n", i); + } + + #endif + } + } + + return True; +} + +void nxagentDisconnectPicture(void * p0, XID x1, void* p2) +{ + PicturePtr pPicture = (PicturePtr) p0; + Bool *pBool = (Bool *) p2; + + #ifdef TEST + fprintf(stderr, "nxagentDisconnectPicture: Called with bool [%d] and picture at [%p].\n", + *pBool, (void *) pPicture); + + fprintf(stderr, "nxagentDisconnectPicture: Virtual picture is [%ld].\n", + nxagentPicture(pPicture)); + #endif + + if (!*pBool || !pPicture) + { + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentDisconnectPicture: %p - XID %lx\n", + (void *) pPicture, nxagentPicture(pPicture)); + #endif + + nxagentPicture(pPicture) = None; +} + +Bool nxagentDisconnectAllPicture() +{ + int i; + Bool r; + + #ifdef DEBUG + fprintf(stderr, "nxagentDisconnectAllPicture.\n"); + #endif + + for (i = 0, r = 1; i < MAXCLIENTS; i++) + { + if (clients[i]) + { + FindClientResourcesByType(clients[i], PictureType, nxagentDisconnectPicture, &r); + + #ifdef WARNING + + if (r == False) + { + fprintf(stderr, "nxagentDisconnectAllPicture: WARNING! Failed to disconnect " + "picture for client [%d].\n", i); + } + + #endif + } + } + + return True; +} + +void nxagentRenderCreateSolidFill(PicturePtr pPicture, xRenderColor *color) +{ + Picture id; + + if (nxagentRenderEnable == False) + { + return; + } + + #ifdef DEBUG + + fprintf(stderr, "nxagentRenderCreateSolidFill: Got called.\n"); + + if (pPicture == NULL) + { + fprintf(stderr, "nxagentRenderCreateSolidFill: WARNING! pPicture pointer is NULL.\n"); + } + + if (color == NULL) + { + fprintf(stderr, "nxagentRenderCreateSolidFill: WARNING! color pointer is NULL.\n"); + } + + #endif /* #ifdef DEBUG */ + + memset(&(nxagentPicturePriv(pPicture) -> lastServerValues), 0, + sizeof(XRenderPictureAttributes_)); + + id = XRenderCreateSolidFill(nxagentDisplay, (XRenderColor *) color); + + #ifdef DEBUG + XSync(nxagentDisplay, 0); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentRenderCreateSolidFill: Created solid fill xid [%lu].\n", id); + #endif + + nxagentPicturePriv(pPicture) -> picture = id; +} + +void nxagentRenderCreateLinearGradient(PicturePtr pPicture, xPointFixed *p1, + xPointFixed *p2, int nStops, + xFixed *stops, + xRenderColor *colors) +{ + Picture id; + + XLinearGradient linearGradient; + + if (nxagentRenderEnable == False) + { + return; + } + + #ifdef DEBUG + + fprintf(stderr, "nxagentRenderCreateLinearGradient: Got called.\n"); + + if (pPicture == NULL) + { + fprintf(stderr, "nxagentRenderCreateLinearGradient: WARNING! pPicture pointer is NULL.\n"); + } + + if (p1 == NULL) + { + fprintf(stderr, "nxagentRenderCreateLinearGradient: WARNING! p1 pointer is NULL.\n"); + } + + if (p2 == NULL) + { + fprintf(stderr, "nxagentRenderCreateLinearGradient: WARNING! p2 pointer is NULL.\n"); + } + + if (stops == NULL) + { + fprintf(stderr, "nxagentRenderCreateLinearGradient: WARNING! stops pointer is NULL.\n"); + } + + if (colors == NULL) + { + fprintf(stderr, "nxagentRenderCreateLinearGradient: WARNING! colors pointer is NULL.\n"); + } + + #endif /* #ifdef DEBUG */ + + memset(&(nxagentPicturePriv(pPicture) -> lastServerValues), 0, + sizeof(XRenderPictureAttributes_)); + + linearGradient.p1.x = (XFixed) p1 -> x; + linearGradient.p1.y = (XFixed) p1 -> y; + linearGradient.p2.x = (XFixed) p2 -> x; + linearGradient.p2.y = (XFixed) p2 -> y; + + id = XRenderCreateLinearGradient(nxagentDisplay, &linearGradient, + (XFixed *) stops, + (XRenderColor *) colors, nStops); + + #ifdef DEBUG + XSync(nxagentDisplay, 0); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentRenderCreateLinearGradient: Created linear gradient xid [%lu].\n", id); + #endif + + nxagentPicturePriv(pPicture) -> picture = id; +} + +void nxagentRenderCreateRadialGradient(PicturePtr pPicture, xPointFixed *inner, + xPointFixed *outer, + xFixed innerRadius, + xFixed outerRadius, + int nStops, + xFixed *stops, + xRenderColor *colors) +{ + Picture id; + + XRadialGradient radialGradient; + + if (nxagentRenderEnable == False) + { + return; + } + + #ifdef DEBUG + + fprintf(stderr, "nxagentRenderCreateRadialGradient: Got called.\n"); + + if (pPicture == NULL) + { + fprintf(stderr, "nxagentRenderCreateRadialGradient: WARNING! pPicture pointer is NULL.\n"); + } + + if (inner == NULL) + { + fprintf(stderr, "nxagentRenderCreateRadialGradient: WARNING! inner pointer is NULL.\n"); + } + + if (outer == NULL) + { + fprintf(stderr, "nxagentRenderCreateRadialGradient: WARNING! outer pointer is NULL.\n"); + } + + if (stops == NULL) + { + fprintf(stderr, "nxagentRenderCreateRadialGradient: WARNING! stops pointer is NULL.\n"); + } + + if (colors == NULL) + { + fprintf(stderr, "nxagentRenderCreateRadialGradient: WARNING! colors pointer is NULL.\n"); + } + + #endif /* #ifdef DEBUG */ + + memset(&(nxagentPicturePriv(pPicture) -> lastServerValues), 0, + sizeof(XRenderPictureAttributes_)); + + radialGradient.inner.x = (XFixed) inner -> x; + radialGradient.inner.y = (XFixed) inner -> y; + radialGradient.inner.radius = (XFixed) innerRadius; + radialGradient.outer.x = (XFixed) outer -> x; + radialGradient.outer.y = (XFixed) outer -> y; + radialGradient.outer.radius = (XFixed) outerRadius; + + id = XRenderCreateRadialGradient(nxagentDisplay, &radialGradient, + (XFixed *) stops, + (XRenderColor *) colors, nStops); + + #ifdef DEBUG + XSync(nxagentDisplay, 0); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentRenderCreateRadialGradient: Created radial gradient xid [%lu].\n", id); + #endif + + nxagentPicturePriv(pPicture) -> picture = id; +} + +void nxagentRenderCreateConicalGradient(PicturePtr pPicture, + xPointFixed *center, + xFixed angle, int nStops, + xFixed *stops, + xRenderColor *colors) +{ + Picture id; + + XConicalGradient conicalGradient; + + if (nxagentRenderEnable == False) + { + return; + } + + #ifdef DEBUG + + fprintf(stderr, "nxagentRenderCreateConicalGradient: Got called.\n"); + + if (pPicture == NULL) + { + fprintf(stderr, "nxagentRenderCreateConicalGradient: WARNING! pPicture pointer is NULL.\n"); + } + + if (center == NULL) + { + fprintf(stderr, "nxagentRenderCreateConicalGradient: WARNING! center pointer is NULL.\n"); + } + + if (stops == NULL) + { + fprintf(stderr, "nxagentRenderCreateConicalGradient: WARNING! stops pointer is NULL.\n"); + } + + if (colors == NULL) + { + fprintf(stderr, "nxagentRenderCreateConicalGradient: WARNING! colors pointer is NULL.\n"); + } + + #endif /* #ifdef DEBUG */ + + memset(&(nxagentPicturePriv(pPicture) -> lastServerValues), 0, + sizeof(XRenderPictureAttributes_)); + + conicalGradient.center.x = (XFixed) center -> x; + conicalGradient.center.y = (XFixed) center -> y; + conicalGradient.angle = (XFixed) angle; + + id = XRenderCreateConicalGradient(nxagentDisplay, &conicalGradient, + (XFixed *) stops, + (XRenderColor *) colors, nStops); + + #ifdef DEBUG + XSync(nxagentDisplay, 0); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentRenderCreateConicalGradient: Created conical gradient xid [%lu].\n", id); + #endif + + nxagentPicturePriv(pPicture) -> picture = id; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Render.h b/nx-X11/programs/Xserver/hw/nxagent/Render.h new file mode 100644 index 000000000..1c56ec16b --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Render.h @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Render_H__ +#define __Render_H__ + +#include "screenint.h" +#include "cursor.h" +#include "picture.h" +#include "renderproto.h" + +#include "glyphstr.h" + +#include "Agent.h" + +extern int nxagentRenderEnable; +extern int nxagentRenderVersionMajor; +extern int nxagentRenderVersionMinor; + +extern int nxagentPicturePrivateIndex; + +extern BoxPtr nxagentGlyphsExtents; +extern BoxPtr nxagentTrapezoidExtents; + +/* + * Structure imported from Xrender.h. We don't + * include Xrender.h at this point because of + * clashes of definition. + */ + +/* + * Xlib Pixmap and Atom types are 8 bytes long + * on 64-bit archs, whilst they are 4 bytes long + * on 32-bit ones. At this point, Pixmap and Atom + * are not Xlib types but Xserver ones: here they + * are always 4 bytes long. So that we use XlibID + * symbols defined below to fill the structure with + * fields having the right size. + */ + +typedef struct { + int repeat; + Picture alpha_map; + int alpha_x_origin; + int alpha_y_origin; + int clip_x_origin; + int clip_y_origin; + XlibPixmap clip_mask; + Bool graphics_exposures; + int subwindow_mode; + int poly_edge; + int poly_mode; + XlibAtom dither; + Bool component_alpha; +} XRenderPictureAttributes_; + +typedef struct +{ + Picture picture; + + XRenderPictureAttributes_ lastServerValues; + +} nxagentPrivPictureRec; + +typedef nxagentPrivPictureRec *nxagentPrivPicturePtr; + +#define nxagentPicturePriv(pPicture) \ + ((nxagentPrivPicturePtr) ((pPicture) -> devPrivates[nxagentPicturePrivateIndex].ptr)) + +#define nxagentPicture(pPicture) (nxagentPicturePriv(pPicture) -> picture) + +#define nxagentSetPictureRemoteValue(pPicture, pvalue, value) \ +do \ +{ \ + nxagentPicturePriv(pPicture) -> lastServerValues.pvalue = value; \ +} \ +while (0) + +#define nxagentCheckPictureRemoteValue(pPicture, pvalue, value) \ + (nxagentPicturePriv(pPicture) -> lastServerValues.pvalue == value) + +void nxagentRenderExtensionInit(void); +Bool nxagentPictureInit(ScreenPtr, PictFormatPtr, int); + +int nxagentRenderRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); + +void nxagentAddGlyphs(GlyphSetPtr glyphSet, Glyph *gids, xGlyphInfo *gi, + int nglyphs, CARD8 *images, int sizeImages); + +void nxagentReconnectPicture(void * p0, XID x1, void *p2); +void nxagentDisconnectPicture(void * p0, XID x1, void* p2); + +void nxagentReconnectGlyphSet(void* p0, XID x1, void *p2); + +void nxagentDestroyPicture(PicturePtr pPicture); + +#endif /* __Render_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Rootless.c b/nx-X11/programs/Xserver/hw/nxagent/Rootless.c new file mode 100644 index 000000000..f42f9d99d --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Rootless.c @@ -0,0 +1,1291 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "X.h" + +#include "../../include/window.h" +#include "windowstr.h" +#include "colormapst.h" +#include "scrnintstr.h" +#include "propertyst.h" + +#include "Agent.h" +#include "Display.h" +#include "Drawable.h" +#include "Windows.h" +#include "Pixmaps.h" +#include "Atoms.h" +#include "Trap.h" +#include "Utils.h" + +#include "compext/Compext.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Assigned at the time the root window is + * initialized. + */ + +typedef struct +{ + CARD32 flags; + CARD32 input; + CARD32 initial_state; + CARD32 icon_pixmap; + CARD32 icon_window; + INT32 icon_x; + INT32 icon_y; + CARD32 icon_mask; + CARD32 window_group; +} +nxagentWMHints; + +/* + * This structure is compatible with 32 + * and 64 bit library interface. It has + * been copied from Xatomtype.h and it's + * a parameter of XChangeProperty(). + */ + +typedef struct +{ + unsigned long flags; + long input; + long initialState; + unsigned long iconPixmap; + unsigned long iconWindow; + long iconX; + long iconY; + unsigned long iconMask; + unsigned long windowGroup; +} +nxagentPropWMHints; + +WindowPtr nxagentRootlessWindow = NULL; + +#define TOP_LEVEL_TABLE_UNIT 100 + +typedef struct { + Window xid; + WindowPtr pWin; +} TopLevelParentRec; + +typedef struct { + TopLevelParentRec *elt; + int next; + int size; +} TopLevelParentMap; + +static TopLevelParentMap topLevelParentMap = { NULL, 0, 0 }; + +static void nxagentRemovePropertyFromList(void); + +/* + * This is currently unused. + */ + +#ifdef TEST + +static void nxagentPrintRootlessTopLevelWindowMap(void); + +void nxagentPrintRootlessTopLevelWindowMap() +{ + int i; + + fprintf(stderr, "nxagentPrintRootlessTopLevelWindowMap: Map size is [%d] num of entry [%d].\n", + topLevelParentMap.size, topLevelParentMap.next); + + for (i = 0; i < topLevelParentMap.next; i++) + { + fprintf(stderr, "nxagentPrintRootlessTopLevelWindowMap: [%d] pWin at [%p] XID at [%ld].\n", + i, (void *) topLevelParentMap.elt[i].pWin, (long int) topLevelParentMap.elt[i].xid); + } +} + +#endif + +void nxagentRootlessAddTopLevelWindow(WindowPtr pWin, Window w) +{ + int i; + + for (i = 0; i < topLevelParentMap.next; i++) + { + if (topLevelParentMap.elt[i].pWin == pWin) + { + #ifdef TEST + fprintf(stderr, "nxagentRootlessAddTopLevelWindow: WARNING! " + "Trying to add duplicated entry window at [%p] xid [%ld].\n", + (void *) pWin, w); + #endif + + topLevelParentMap.elt[i].xid = w; + + return; + } + } + + if (topLevelParentMap.next == topLevelParentMap.size) + { + TopLevelParentRec *ptr = topLevelParentMap.elt; + size_t size = (topLevelParentMap.size += TOP_LEVEL_TABLE_UNIT); + + ptr = realloc(ptr, size * sizeof(TopLevelParentRec)); + + if (ptr == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentRootlessAddTopLevelWindow: Warning failed to allocate memory.\n"); + #endif + + return; + } + + topLevelParentMap.elt = ptr; + topLevelParentMap.size = size; + } + + topLevelParentMap.elt[topLevelParentMap.next].xid = w; + topLevelParentMap.elt[topLevelParentMap.next].pWin = pWin; + topLevelParentMap.next++; +} + +WindowPtr nxagentRootlessTopLevelWindow(Window w) +{ + int i; + + for (i = 0; i < topLevelParentMap.next; i++) + { + if (w == topLevelParentMap.elt[i].xid) + { + return topLevelParentMap.elt[i].pWin; + } + } + + return NULL; +} + +void nxagentRootlessDelTopLevelWindow(WindowPtr pWin) +{ + int i; + + for (i = 0; i < topLevelParentMap.next; i++) + { + if (pWin == topLevelParentMap.elt[i].pWin) + { + topLevelParentMap.elt[i] = topLevelParentMap.elt[topLevelParentMap.next - 1]; + topLevelParentMap.next--; + + return; + } + } +} + +Window nxagentRootlessWMTopLevelWindow(WindowPtr pWin); + +void nxagentConfigureRootlessWindow(WindowPtr pWin, int x, int y, int w, int h, int bw, + WindowPtr pSib, int stack_mode, Mask mask) +{ + XWindowChanges changes; + Window sibw = 0; + + changes.x = x; + changes.y = y; + changes.width = w; + changes.height = h; + changes.border_width = bw; + changes.stack_mode = stack_mode; + + if (pSib) + { + sibw = nxagentWindow(pSib); + } + + if (sibw) + { + changes.sibling = sibw; + } + + XConfigureWindow(nxagentDisplay, nxagentWindow(pWin), mask, &changes); +} + +void nxagentCirculateRootlessWindows(int direction) +{ + XCirculateSubwindows(nxagentDisplay, DefaultRootWindow(nxagentDisplay), direction); +} + +#ifdef DEBUG + +Bool nxagentRootlessTreesMatch() +{ + Window root_return; + Window parent_return; + Window *children_return; + unsigned int nChildrenReturn; + WindowPtr pW; + WindowPtr pTestWin = screenInfo.screens[0]->root -> firstChild; + Bool treesMatch = True; + Status result; + + result = XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + &root_return, &parent_return, &children_return, &nChildrenReturn); + + if (!result) + { + #ifdef WARNING + fprintf(stderr, "nxagentRootlessTreesMatch: WARNING! Failed QueryTree request.\n"); + #endif + + return False; + } + + while (nChildrenReturn > 0) + { + pW = nxagentWindowPtr(children_return[--nChildrenReturn]); + + if (!pW) + { + pW = nxagentRootlessTopLevelWindow(children_return[nChildrenReturn]); + } + + if (pW && pW != screenInfo.screens[0]->root) + { + if (treesMatch && pTestWin && pTestWin == pW) + { + pTestWin = pTestWin -> nextSib; + } + else + { + treesMatch = False; + } + } + } + + if (children_return) + { + XFree(children_return); + } + + return treesMatch; +} + +#endif + +#ifndef _XSERVER64 +void nxagentRootlessRestack(Window children[], unsigned int nchildren) +#else +void nxagentRootlessRestack(unsigned long children[], unsigned int nchildren) +#endif +{ + WindowPtr *toplevel; + unsigned int ntoplevel; + int i; + WindowPtr pWin; + ClientPtr pClient; + XID values[2]; + Mask mask; + + toplevel = malloc(sizeof(WindowPtr) * nchildren); + + if (!toplevel) + { + /* FIXME: Is this too much and we and simply return here? */ + FatalError("nxagentRootlessRestack: malloc() failed."); + } + + ntoplevel = 0; + + for(i = 0; i < nchildren; i++) + { + pWin = nxagentWindowPtr(children[i]); + + if (!pWin) + { + pWin = nxagentRootlessTopLevelWindow(children[i]); + } + + if (pWin && pWin != screenInfo.screens[0]->root) + { + toplevel[ntoplevel++] = pWin; + } + } + + if (!ntoplevel) + { + free(toplevel); + return; + } + + #ifdef DEBUG + + fprintf(stderr, "nxagentRootlessRestack: External top level windows before restack:"); + + for (i = 0; i < ntoplevel; i++) + { + fprintf(stderr, "nxagentRootlessRestack: [%p]\n", toplevel[i]); + } + + fprintf(stderr, "nxagentRootlessRestack: Internal top level windows before restack:"); + + for (pWin = screenInfo.screens[0]->root -> firstChild; pWin != NULL; pWin = pWin -> nextSib) + { + fprintf(stderr, "nxagentRootlessRestack: [%p]\n", pWin); + } + + #endif + + pWin = screenInfo.screens[0]->root -> firstChild; + + values[1] = (XID) Above; + + while(ntoplevel-- > 0 && pWin != NULL) + { + if (toplevel[ntoplevel] != pWin) + { + mask = CWSibling | CWStackMode; + values[0] = pWin -> drawable.id; + pClient = wClient(toplevel[ntoplevel]); + nxagentScreenTrap = 1; + ConfigureWindow(toplevel[ntoplevel], mask, (XID *) values, pClient); + nxagentScreenTrap = 0; + + #ifdef TEST + fprintf(stderr, "nxagentRootlessRestack: Restacked window [%p].\n", (void*) toplevel[ntoplevel]); + #endif + } + + pWin = toplevel[ntoplevel] -> nextSib; + } + + #ifdef DEBUG + + fprintf(stderr, "nxagentRootlessRestack: External top level windows after restack:"); + + ntoplevel = i; + + for (i = 0; i < ntoplevel; i++) + { + fprintf(stderr, "nxagentRootlessRestack: [%p]\n", toplevel[i]); + } + + fprintf(stderr, "nxagentRootlessRestack: Internal top level windows after restack:"); + + for (pWin = screenInfo.screens[0]->root -> firstChild; pWin != NULL; pWin = pWin -> nextSib) + { + fprintf(stderr, "nxagentRootlessRestack: [%p]\n", pWin); + } + + #endif + + free(toplevel); + + return; +} + +/* + * Determine if window is a top-level window. + */ + +Window nxagentRootlessWindowParent(WindowPtr pWin) +{ + #ifdef TEST + fprintf(stderr, "nxagentRootlessWindowParent: Called for window at [%p][%ld] with parent [%p][%ld].\n", + (void *) pWin, nxagentWindowPriv(pWin)->window, (void *) pWin->parent, + (pWin->parent ? nxagentWindowPriv(pWin->parent)->window : 0)); + #endif + + if (pWin -> parent == NULL) + { + return DefaultRootWindow(nxagentDisplay); + } + else if (pWin -> parent == nxagentRootlessWindow) + { + return DefaultRootWindow(nxagentDisplay); + } + else + { + return nxagentWindow(pWin -> parent); + } +} + +int nxagentExportAllProperty(pWin) + WindowPtr pWin; +{ + PropertyPtr pProp; + int total = 0; + + for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) + { + total += nxagentExportProperty(pWin, + pProp->propertyName, + pProp->type, + pProp->format, + PropModeReplace, + pProp->size, + pProp->data); + } + + return total; +} + +int nxagentExportProperty(pWin, property, type, format, mode, nUnits, value) + WindowPtr pWin; + Atom property, type; + int format, mode; + unsigned long nUnits; + void *value; +{ + const char *propertyS, *typeS; + Atom propertyX, typeX; + char *output = NULL; + nxagentWMHints wmHints; + nxagentPropWMHints propHints; + Bool export = False; + Bool freeMem = False; + + if (NXDisplayError(nxagentDisplay) == 1) + { + return 0; + } + + propertyS = NameForAtom(property); + typeS = NameForAtom(type); + + if (strncmp(propertyS, "WM_", 3) != 0 && + strncmp(propertyS, "_NET_", 5) != 0 && + strcmp(propertyS, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR") != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentExportProperty: WARNING! Ignored ChangeProperty " + "on %swindow %lx property %s type %s nUnits %ld format %d\n", + nxagentWindowTopLevel(pWin) ? "toplevel " : "", nxagentWindow(pWin), + validateString(propertyS), validateString(typeS), nUnits, format); + #endif + } + else if (strcmp(typeS, "STRING") == 0 || + #ifndef _XSERVER64 + strcmp(typeS, "CARDINAL") == 0 || + strcmp(typeS, "WM_SIZE_HINTS") == 0 || + #endif + strcmp(typeS, "UTF8_STRING") == 0) + { + output = value; + export = True; + } + #ifdef _XSERVER64 + else if (strcmp(typeS, "CARDINAL") == 0 || strcmp(typeS, "WM_SIZE_HINTS") == 0) + { + /* FIXME: is it okay here to ignore malloc fails? */ + unsigned long *buffer = malloc(nUnits * sizeof(*buffer)); + int *input = value; + int i; + + if (buffer) + { + freeMem = True; + export = True; + output = (char*) buffer; + + for (i = 0; i < nUnits; i++) + { + buffer[i] = input[i]; + } + } + } + #endif + else if (strcmp(typeS, "WM_HINTS") == 0) + { + ClientPtr pClient = wClient(pWin); + wmHints = *(nxagentWMHints*)value; + + wmHints.flags |= InputHint; + wmHints.input = True; + + /* + * Initialize the structure used in XChangeProperty(). + */ + + propHints.flags = wmHints.flags; + propHints.input = (wmHints.input == True ? 1 : 0); + propHints.initialState = wmHints.initial_state; + propHints.iconPixmap = wmHints.icon_pixmap; + propHints.iconWindow = wmHints.icon_window; + propHints.iconX = wmHints.icon_x; + propHints.iconY = wmHints.icon_y; + propHints.iconMask = wmHints.icon_mask; + propHints.windowGroup = wmHints.window_group; + + output = (char*) &propHints; + export = True; + + if ((wmHints.flags & IconPixmapHint) && (wmHints.icon_pixmap != None)) + { + PixmapPtr icon = (PixmapPtr)SecurityLookupIDByType(pClient, wmHints.icon_pixmap, + RT_PIXMAP, DixDestroyAccess); + + if (icon) + { + if (nxagentDrawableStatus((DrawablePtr) icon) == NotSynchronized) + { + nxagentSynchronizeRegion((DrawablePtr) icon, NullRegion, NEVER_BREAK, NULL); + } + + propHints.iconPixmap = nxagentPixmap(icon); + } + else + { + propHints.flags &= ~IconPixmapHint; + + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! Failed to look up icon pixmap %x from hint " + "exporting property %s type %s on window %p.\n", + (unsigned int) wmHints.icon_pixmap, propertyS, typeS, + (void *) pWin); + #endif + } + } + + if ((wmHints.flags & IconWindowHint) && (wmHints.icon_window != None)) + { + WindowPtr icon = (WindowPtr)SecurityLookupWindow(wmHints.icon_window, pClient, + DixDestroyAccess); + + if (icon) + { + propHints.iconWindow = nxagentWindow(icon); + } + else + { + propHints.flags &= ~IconWindowHint; + + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! Failed to look up icon window %x from hint " + "exporting property %s type %s on window %p.\n", + (unsigned int) wmHints.icon_window, propertyS, typeS, + (void *) pWin); + #endif + } + } + + if ((wmHints.flags & IconMaskHint) && (wmHints.icon_mask != None)) + { + PixmapPtr icon = (PixmapPtr)SecurityLookupIDByType(pClient, wmHints.icon_mask, + RT_PIXMAP, DixDestroyAccess); + + if (icon) + { + propHints.iconMask = nxagentPixmap(icon); + } + else + { + propHints.flags &= ~IconMaskHint; + + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! Failed to look up icon mask %x from hint " + "exporting property %s type %s on window %p.\n", + (unsigned int) wmHints.icon_mask, propertyS, typeS, + (void *) pWin); + #endif + } + } + + if ((wmHints.flags & WindowGroupHint) && (wmHints.window_group != None)) + { + WindowPtr window = (WindowPtr)SecurityLookupWindow(wmHints.window_group, pClient, + DixDestroyAccess); + + if (window) + { + propHints.windowGroup = nxagentWindow(window); + } + else + { + propHints.flags &= ~WindowGroupHint; + + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! Failed to look up window group %x from hint " + "exporting property %s type %s on window %p.\n", + (unsigned int) wmHints.window_group, propertyS, typeS, + (void *) pWin); + #endif + } + } + } + else if (strcmp(typeS, "ATOM") == 0) + { + XlibAtom *atoms = malloc(nUnits * sizeof(*atoms)); + Atom *input = value; + const char *atomName = NULL; + int i; + int j = 0; + + if (!atoms) + { + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! malloc() failed for '%s'- bailing out.\n", typeS); + #endif + return False; + } + + freeMem = True; + export = True; + output = (char *) atoms; + + for (i = 0; i < nUnits; i++) + { + /* + * Exporting the _NET_WM_PING property could + * result in rootless windows being grayed out + * when the compiz window manager is running. + * + * Better solution would probably be to handle + * the communication with the window manager + * instead of just getting rid of the property. + */ + + if ((atomName = NameForAtom(input[i])) != NULL && + strcmp(atomName, "_NET_WM_PING") != 0) + { + atoms[j] = nxagentLocalToRemoteAtom(input[i]); + + if (atoms[j] == None) + { + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! Failed to convert local atom %ld [%s].\n", + (long int) input[i], validateString(atomName)); + #endif + } + + j++; + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentExportProperty: WARNING! " + "Not exporting the _NET_WM_PING property.\n"); + } + #endif + } + + nUnits = j; + } + else if (strcmp(typeS, "WINDOW") == 0) + { + Window *input = value; + XlibWindow *wind = malloc(nUnits * sizeof(*wind)); + ClientPtr pClient = wClient(pWin); + WindowPtr pWindow; + int i; + + if (!wind) + { + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! malloc() failed for '%s' - bailing out.\n", typeS); + #endif + return False; + } + + freeMem = True; + export = True; + output = (char*) wind; + + for (i = 0; i < nUnits; i++) + { + pWindow = (WindowPtr)SecurityLookupWindow(input[i], pClient, + DixDestroyAccess); + if ((input[i] != None) && pWindow) + { + wind[i] = nxagentWindow(pWindow); + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! Failed to look up window %ld " + "exporting property %s type %s on window %p.\n", + (long int) input[i], propertyS, typeS, (void *) pWin); + #endif + + /* + * It seems that clients specifie + * strange windows, perhaps are + * not real windows so we can try + * to let them pass anyway. + * + * wind[i] = None; + * + */ + } + } + } + + if (export) + { + propertyX = nxagentLocalToRemoteAtom(property); + typeX = nxagentLocalToRemoteAtom(type); + + if (propertyX == None || typeX == None) + { + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! Failed to convert local atom.\n"); + #endif + + export = 0; + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentExportProperty: Property [%lu] format [%i] " + "units [%lu].\n", propertyX, format, nUnits); + #endif + + if ((format >> 3) * nUnits + sizeof(xChangePropertyReq) < + (MAX_REQUEST_SIZE << 2)) + { + XChangeProperty(nxagentDisplay, nxagentWindow(pWin), propertyX, typeX, + format, mode, (void*)output, nUnits); + } + else if (mode == PropModeReplace) + { + int n; + char *data; + + XDeleteProperty(nxagentDisplay, nxagentWindow(pWin), propertyX); + + data = (char *) output; + + while (nUnits > 0) + { + if ((format >> 3) * nUnits + sizeof(xChangePropertyReq) < + (MAX_REQUEST_SIZE << 2)) + { + n = nUnits; + } + else + { + n = ((MAX_REQUEST_SIZE << 2) - sizeof(xChangePropertyReq)) / + (format >> 3); + } + + XChangeProperty(nxagentDisplay, nxagentWindow(pWin), propertyX, + typeX, format, PropModeAppend, (void*) data, n); + + nUnits -= n; + + data = (char *) data + n * (format >> 3); + } + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentExportProperty: WARNING! " + "Property [%lu] too long.\n", (long unsigned int)propertyX); + #endif + + goto nxagentExportPropertyError; + } + + nxagentAddPropertyToList(propertyX, pWin); + } + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentExportProperty: WARNING! Ignored ChangeProperty " + "on %swindow %x property %s type %s nUnits %ld format %d\n", + nxagentWindowTopLevel(pWin) ? "toplevel " : "", + nxagentWindow(pWin), validateString(propertyS), validateString(typeS), + nUnits, format); + #endif + } + + nxagentExportPropertyError: + + if (freeMem) + { + free(output); + } + + return export; +} + +void nxagentImportProperty(Window window, + Atom property, + Atom type, + int format, + unsigned long nitems, + unsigned long bytes_after, + unsigned char *buffer) +{ + Atom propertyL; + Atom typeL; + + WindowPtr pWin; + Bool import = False; + Bool freeMem = False; + nxagentWMHints wmHints; + + typedef struct { + CARD32 state; + Window icon; + } WMState; + WMState wmState; + + char *output = NULL; + const char *typeS; + + pWin = nxagentWindowPtr(window); + + if (pWin == NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentImportProperty: Failed to look up remote window %lx property [%ld] exiting.\n", + window, property); + #endif + + return; + } + + propertyL = nxagentRemoteToLocalAtom(property); + + if (!ValidAtom(propertyL)) + { + #ifdef TEST + fprintf(stderr, "nxagentImportProperty: Failed to convert remote property atom.\n"); + #endif + + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentImportProperty: Window %lx property [%ld]: %s\n", + window, property, validateString(NameForAtom(propertyL))); + #endif + + /* + * We settle a property size limit of + * 256K beyond which we simply ignore them. + */ + + typeL = nxagentRemoteToLocalAtom(type); + typeS = NameForAtom(typeL); + + if (buffer == NULL && (nitems > 0)) + { + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: Failed to retrieve remote property [%ld] %s on Window %ld\n", + (long int) property, validateString(NameForAtom(propertyL)), (long int) window); + #endif + } + else if (bytes_after != 0) + { + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: Remote property bigger than maximum limits.\n"); + #endif + } + else if (!ValidAtom(typeL)) + { + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: Failed to convert remote atoms [%ld].\n", + (long int) type); + #endif + } + else if (nitems == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentImportProperty: Importing void property.\n"); + #endif + + import = True; + } + else if (strcmp(typeS, "STRING") == 0 || + strcmp(typeS, "UTF8_STRING") == 0 || + strcmp(typeS, "CARDINAL") == 0 || + strcmp(typeS, "WM_SIZE_HINTS") == 0) + { + output = (char*)buffer; + import = True; + } + else if (strcmp(typeS, "WM_STATE") == 0) + { + /* + * Contents of property of type WM_STATE + * are {CARD32 state, WINDOW icon}. Only + * the icon field has to be modified before + * importing the property. + */ + + WindowPtr pIcon; + + wmState = *(WMState*)buffer; + pIcon = nxagentWindowPtr(wmState.icon); + + if (pIcon || wmState.icon == None) + { + import = True; + output = (char*) &wmState; + wmState.icon = pIcon ? nxagentWindow(pIcon) : None; + } + else if (wmState.icon) + { + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: WARNING! Failed to convert remote window %ld" + " importing property %ld of type WM_STATE", (long int) wmState.icon, + (long int) property); + #endif + } + } + else if (strcmp(typeS, "WM_HINTS") == 0) + { + wmHints = *(nxagentWMHints*)buffer; + output = (char*) &wmHints; + import = True; + + if ((wmHints.flags & IconPixmapHint) && (wmHints.icon_pixmap != None)) + { + PixmapPtr icon = nxagentPixmapPtr(wmHints.icon_pixmap); + + if (icon) + { + wmHints.icon_pixmap = icon -> drawable.id; + } + else + { + wmHints.flags &= ~IconPixmapHint; + + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: WARNING! Failed to look up remote icon " + "pixmap %d from hint importing property [%ld] type %s on window %p.\n", + (unsigned int) wmHints.icon_pixmap, (long int) property, + typeS, (void *) pWin); + #endif + } + } + + if ((wmHints.flags & IconWindowHint) && (wmHints.icon_window != None)) + { + WindowPtr icon = nxagentWindowPtr(wmHints.icon_window); + + if (icon) + { + wmHints.icon_window = icon -> drawable.id; + } + else + { + wmHints.flags &= ~IconWindowHint; + + #ifdef WARNING + fprintf(stderr, "nxagenImportProperty: WARNING! Failed to look up remote icon " + "window %x from hint importing property [%ld] type %s on window %p.\n", + (unsigned int) wmHints.icon_window, + (long int) property, typeS, (void *) pWin); + #endif + } + } + + if ((wmHints.flags & IconMaskHint) && (wmHints.icon_mask != None)) + { + PixmapPtr icon = nxagentPixmapPtr(wmHints.icon_mask); + + if (icon) + { + wmHints.icon_mask = icon -> drawable.id; + } + else + { + wmHints.flags &= ~IconMaskHint; + + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: WARNING! Failed to look up remote icon " + "mask %x from hint importing property [%ld] type %s on window %p.\n", + (unsigned int) wmHints.icon_mask, (long int) property, typeS, (void *) pWin); + #endif + } + } + + if ((wmHints.flags & WindowGroupHint) && (wmHints.window_group != None)) + { + WindowPtr group = nxagentWindowPtr(wmHints.window_group); + + if (group) + { + wmHints.window_group = group -> drawable.id; + } + else + { + wmHints.flags &= ~WindowGroupHint; + + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: WARNING! Failed to look up remote window " + "group %x from hint importing property [%ld] type %s on window %p.\n", + (unsigned int) wmHints.window_group, + (long int) property, typeS, (void *) pWin); + #endif + } + } + } + else if (strcmp(typeS, "ATOM") == 0) + { + Atom *atoms = malloc(nitems * sizeof(Atom)); + Atom *input = (Atom*) buffer; + int i; + + if (atoms == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: WARNING! malloc() failed for '%s' - bailing out.\n", typeS); + #endif + + return; + } + + freeMem = True; + import = True; + output = (char *) atoms; + + for (i = 0; i < nitems; i++) + { + atoms[i] = nxagentRemoteToLocalAtom(input[i]); + + if (atoms[i] == None) + { + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: WARNING! Failed to convert remote atom %ld.\n", + (long int) input[i]); + #endif + } + } + } + else if (strcmp(typeS, "WINDOW") == 0) + { + Window *input = (Window*) buffer; + Window *wind = malloc(nitems * sizeof(Window)); + WindowPtr pWindow; + int i; + + if (!wind) + { + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: WARNING! malloc() failed for '%s' - bailing out.\n", typeS); + #endif + + return; + } + freeMem = True; + import = True; + output = (char*) wind; + + for (i = 0; i < nitems; i++) + { + pWindow = nxagentWindowPtr(input[i]); + + if (pWindow) + { + wind[i] = pWindow -> drawable.id; + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentImportProperty: WARNING! Failed to look up remote window %lx " + "importing property [%ld] type %s on window %p.\n", + (long int) input[i], (long int) property, typeS, (void*)pWin); + #endif + + wind[i] = None; + } + } + } + + if (import) + { + #ifdef TEST + fprintf(stderr, "nxagentImportProperty: ChangeProperty " + "on window %lx property [%ld] type %s nitems %ld format %d\n", + window, property, typeS, nitems, format); + #endif + + ChangeWindowProperty(pWin, propertyL, typeL, format, + PropModeReplace, nitems, output, 1); + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentImportProperty: WARNING! Ignored ChangeProperty " + "on window %lx property [%ld] type %s ntems %ld format %d\n", + window, property, validateString(typeS), nitems, format); + #endif + } + + if (freeMem) + { + free(output); + } + + return; +} + +/* + * We want to import all properties changed by external clients to + * reflect properties of our internal windows but we must ignore + * all the property notify events generated by our own requests. + * For this purpose we implement a FIFO to record every change pro- + * perty request that we dispatch. In this way, when processing a + * property notify, we can distinguish between the notifications + * generated by our requests from those generated by other clients + * connected to the real X server. + */ + +struct nxagentPropertyRec{ + Window window; + Atom property; + struct nxagentPropertyRec *next; +}; + +static struct{ + struct nxagentPropertyRec *first; + struct nxagentPropertyRec *last; + int size; +} nxagentPropertyList = {NULL, NULL, 0}; + +/* + * Removing first element from list. + */ + +void nxagentRemovePropertyFromList() +{ + struct nxagentPropertyRec *tmp = nxagentPropertyList.first; + + #ifdef TEST + fprintf(stderr, "nxagentRemovePropertyFromList: Property %ld on Window %lx to list, list size is %d.\n\n", + nxagentPropertyList.first -> property, nxagentPropertyList.first -> window, + nxagentPropertyList.size); + #endif + + if (nxagentPropertyList.first) + { + nxagentPropertyList.first = nxagentPropertyList.first -> next; + + if (--nxagentPropertyList.size == 0) + { + nxagentPropertyList.last = NULL; + } + + free(tmp); + } +} + +/* + * Add the record to the list. + */ + +void nxagentAddPropertyToList(Atom property, WindowPtr pWin) +{ + struct nxagentPropertyRec *tmp; + + if (NXDisplayError(nxagentDisplay) == 1) + { + return; + } + + if ((tmp = malloc(sizeof(struct nxagentPropertyRec))) == NULL) + { + FatalError("nxagentAddPropertyToList: malloc() failed."); + } + + #ifdef TEST + fprintf(stderr, "nxagentAddPropertyToList: Adding record Property %ld - Window %lx[%p]" + "to list, list size is %d.\n", property, nxagentWindow(pWin), (void*) pWin, + nxagentPropertyList.size); + #endif + + tmp -> property = property; + tmp -> window = nxagentWindow(pWin); + tmp -> next = NULL; + + if (nxagentPropertyList.size == 0) + { + nxagentPropertyList.first = tmp; + } + else + { + nxagentPropertyList.last -> next = tmp; + } + + nxagentPropertyList.last = tmp; + nxagentPropertyList.size++; +} + +void nxagentFreePropertyList() +{ + while (nxagentPropertyList.size != 0) + { + nxagentRemovePropertyFromList(); + } +} + +/* + * We are trying to distinguish notify generated by + * an external client from those genarated by our + * own requests. + */ + +Bool nxagentNotifyMatchChangeProperty(void *p) +{ + struct nxagentPropertyRec *first = nxagentPropertyList.first; + XPropertyEvent *X = p; + + #ifdef TEST + fprintf(stderr, "nxagentNotifyMatchChangeProperty: Property notify on window %lx property %ld.\n", + X -> window, X -> atom); + + if (first) + { + fprintf(stderr, "nxagentNotifyMatchChangeProperty: First element on list is window %lx property %ld list size is %d.\n", + first -> window, first -> property, nxagentPropertyList.size); + } + else + { + fprintf(stderr, "nxagentNotifyMatchChangeProperty: List is empty.\n"); + } + #endif + + if (first == NULL || + X -> window != first -> window || + X -> atom != first -> property) + { + return False; + } + + nxagentRemovePropertyFromList(); + + return True; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Rootless.h b/nx-X11/programs/Xserver/hw/nxagent/Rootless.h new file mode 100644 index 000000000..062e164f4 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Rootless.h @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Rootless_H__ +#define __Rootless_H__ + +#include "window.h" + +/* + * The real X server's root window if we + * are in rootless mode. + */ + +extern WindowPtr nxagentRootlessWindow; + +/* + * We want to import all properties changed by external clients to + * reflect properties of our internal windows but we must ignore + * all the property notify events generated by our own requests. + * For this purpose we implement a FIFO to record every change pro- + * perty request that we dispatch. In this way, when processing a + * property notify, we can distinguish between the notifications + * generated by our requests from those generated by other clients + * connected to the real X server. + */ + +typedef struct +{ + Window window; + Atom property; +} PropertyRequestRec; + +extern PropertyRequestRec nxagentPropertyRequests[256]; + +Window nxagentRootlessWindowParent(WindowPtr pWin); + +void nxagentRootlessAddTopLevelWindow(WindowPtr pWin, Window w); +void nxagentRootlessDelTopLevelWindow(WindowPtr pWin); + +WindowPtr nxagentRootlessTopLevelWindow(Window w); + +#ifndef _XSERVER64 +void nxagentRootlessRestack(Window *toplevel, unsigned int ntoplevel); +#else +void nxagentRootlessRestack(unsigned long *toplevel, unsigned int ntoplevel); +#endif + + +int nxagentExportAllProperty(WindowPtr pWin); + +int nxagentExportProperty(WindowPtr pWin, Atom property, Atom type, int format, + int mode, unsigned long nUnits, void * value); + +#define MAX_RETRIEVED_PROPERTY_SIZE 256 * 1024 + +void nxagentImportProperty(Window window, Atom property, Atom type, int format, + unsigned long nitems, unsigned long bytes_after, unsigned char *buffer); + +/* + * Push last ChangeProperty to the list. + */ + +void nxagentAddPropertyToList(Atom property, WindowPtr pWin); + +/* + * Check if a PropertyNotify match the top + * of the list. + */ + +Bool nxagentNotifyMatchChangeProperty(void *X); + +void nxagentConfigureRootlessWindow(WindowPtr pWin, int x, int y, int w, int h, int bw, + WindowPtr pSib, int stack_mode, Mask mask); + +void nxagentCirculateRootlessWindows(int direction); + +void nxagentFreePropertyList(void); + +#endif /* __Rootless_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Screen.c b/nx-X11/programs/Xserver/hw/nxagent/Screen.c new file mode 100644 index 000000000..1c3e76580 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Screen.c @@ -0,0 +1,4741 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +/* + * Used by the auto-disconnect feature. + */ + +#include <signal.h> + +#include "scrnintstr.h" +#include "dix.h" +#include "dixstruct.h" +#include "mi.h" +#include "micmap.h" +#include "colormapst.h" +#include "resource.h" +#include "mipointer.h" +#include "../../fb/fb.h" +#include "../../randr/randrstr.h" +#include "inputstr.h" +#include "mivalidate.h" + +#include "Agent.h" +#include "Display.h" +#include "Screen.h" +#include "Extensions.h" +#include "Atoms.h" +#include "GCs.h" +#include "GCOps.h" +#include "Image.h" +#include "Drawable.h" +#include "Font.h" +#include "Colormap.h" +#include "Cursor.h" +#include "Visual.h" +#include "Events.h" +#include "Init.h" +#include "Args.h" +#include "Client.h" +#include "Options.h" +#include "Splash.h" +#include "Holder.h" +#include "Render.h" +#include "Trap.h" +#include "Keyboard.h" +#include "Pointer.h" +#include "Reconnect.h" +#include "Composite.h" +#include <nx/Shadow.h> +#include "Utils.h" + +#include <nx-X11/Xlib.h> +#include "X11/include/Xinerama_nxagent.h" + + +#define GC XlibGC +#define Font XlibFont +#define KeySym XlibKeySym +#define XID XlibXID +#include <nx-X11/Xlibint.h> +#undef GC +#undef Font +#undef KeySym +#undef XID + +#include "Xatom.h" +#include "Xproto.h" + +#include "compext/Compext.h" + +#include "mibstorest.h" + +/* + * Set here the required log level. + */ + +#undef PANIC +#undef WARNING +#undef TEST +#undef DEBUG +#undef WATCH +#undef DUMP + +/* + * Display a pixmap on an shadow + * display used for debug. + */ + +#ifdef DUMP + +void nxagentShowPixmap(PixmapPtr pPixmap, int x, int y, int width, int height); + +void nxagentFbRestoreArea(PixmapPtr pPixmap, WindowPtr pWin, int xSrc, int ySrc, int width, + int height, int xDst, int yDst) +#endif + +#ifdef WATCH +#include "unistd.h" +#endif + +extern Bool nxagentIpaq; +extern Pixmap nxagentIconPixmap; +extern Pixmap nxagentIconShape; +extern Bool useXpmIcon; + +Window nxagentDefaultWindows[MAXSCREENS]; +Window nxagentInputWindows[MAXSCREENS]; +Window nxagentScreenSaverWindows[MAXSCREENS]; + +#ifdef NXAGENT_ONSTART +Atom nxagentWMStart; +Window nxagentSplashWindow = None; +Pixmap nxagentPixmapLogo; +#endif + +ScreenPtr nxagentDefaultScreen = NULL; +int nxagentArgc = 0; +char **nxagentArgv = NULL; + +#ifdef NXAGENT_ARTSD + +char mcop_atom[] = "MCOPGLOBALS"; +Atom mcop_local_atom = None; +unsigned char fromHexNibble(char c); +void nxagentPropagateArtsdProperties(ScreenPtr pScreen, char *port); + +#endif + +Window nxagentIconWindow = None; +Window nxagentFullscreenWindow = None; + +#ifdef VIEWPORT_FRAME + +WindowPtr nxagentViewportFrameLeft; +WindowPtr nxagentViewportFrameRight; +WindowPtr nxagentViewportFrameAbove; +WindowPtr nxagentViewportFrameBelow; + +#endif /* #ifdef VIEWPORT_FRAME */ + +Bool nxagentCreateScreenResources(ScreenPtr pScreen); +void nxagentPrintAgentGeometry(char *hdrMessage, char *prefix); + + +/* + * These variables are for shadowing feature. + */ + +int nxagentShadowResize = 0; + +WindowPtr nxagentShadowWindowPtr = NULL; + +static XID accessPixmapID; +static Window accessWindowID; +static int imageByteOrder; +static unsigned char nxagentMasterDepth; +static unsigned char nxagentCheckDepth = 0; +static unsigned int nxagentBppShadow; +static unsigned int nxagentBppMaster; +int nxagentShadowXConnectionNumber; +GCPtr nxagentShadowGCPtr = NULL; +PixmapPtr nxagentShadowPixmapPtr = NULL; +char * nxagentShadowBuffer; +unsigned char nxagentShadowDepth; +int nxagentShadowWidth; +int nxagentShadowHeight; +Display * nxagentShadowDisplay; +short nxagentShadowUid = -1; + +void nxagentShadowAdaptDepth(unsigned int, unsigned int, unsigned int, char **); + +RegionRec nxagentShadowUpdateRegion; + +#define NXAGENT_DEFAULT_DPI 75 + +/* + * From randr/randr.c. This was originally static + * but we need it here. + */ + +int TellChanged(WindowPtr pWin, void * value); + +int nxagentBitsPerPixel(int depth) +{ + if (depth == 1) return 1; + else if (depth <= 8) return 8; + else if (depth <= 16) return 16; + else return 32; +} + +void nxagentSetScreenInfo(ScreenInfo *screenInfo) +{ + /* + * Setup global screen info parameters. In the Xnest + * server this stuff is done after having opened the + * real display as Xnest lets the screen reflect the + * order of the remote end. Agent will instead set + * the order according to local endianess and swap + * data whenever it is appropriate. + * + * From a standard implementation: + * + * screenInfo->imageByteOrder = IMAGE_BYTE_ORDER; + * screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + * screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + * screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; + * + * From Xnest implementation: + * + * screenInfo -> imageByteOrder = ImageByteOrder(nxagentDisplay); + * screenInfo -> bitmapScanlineUnit = BitmapUnit(nxagentDisplay); + * screenInfo -> bitmapScanlinePad = BitmapPad(nxagentDisplay); + * screenInfo -> bitmapBitOrder = BitmapBitOrder(nxagentDisplay); + */ + + screenInfo -> imageByteOrder = IMAGE_BYTE_ORDER; + screenInfo -> bitmapScanlinePad = BITMAP_SCANLINE_PAD; + screenInfo -> bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + screenInfo -> bitmapBitOrder = BITMAP_BIT_ORDER; + + #ifdef TEST + fprintf(stderr, "nxagentSetScreenInfo: Server image order is [%d] bitmap order is [%d].\n", + screenInfo -> imageByteOrder, screenInfo -> bitmapBitOrder); + + fprintf(stderr, "nxagentSetScreenInfo: Server scanline unit is [%d] scanline pad is [%d].\n", + screenInfo -> bitmapScanlineUnit, screenInfo -> bitmapScanlinePad); + #endif +} + +void nxagentSetPixmapFormats(ScreenInfo *screenInfo) +{ + int i; + + /* + * Formats are created with no care of which are supported + * on the real display. Creating only formats supported + * by the remote end makes troublesome handling migration + * of session from a display to another. + */ + + screenInfo -> numPixmapFormats = nxagentNumPixmapFormats; + + for (i = 0; i < nxagentNumPixmapFormats; i++) + { + screenInfo -> formats[i].depth = nxagentPixmapFormats[i].depth; + screenInfo -> formats[i].bitsPerPixel = nxagentPixmapFormats[i].bits_per_pixel; + screenInfo -> formats[i].scanlinePad = nxagentPixmapFormats[i].scanline_pad; + + #ifdef TEST + fprintf(stderr, "nxagentSetPixmapFormats: Set format at index [%d] to depth [%d] " + "bits per pixel [%d] scanline pad [%d].\n", i, + screenInfo -> formats[i].depth, screenInfo -> formats[i].bitsPerPixel, + screenInfo -> formats[i].scanlinePad); + #endif + } +} + +void nxagentMinimizeFromFullScreen(ScreenPtr pScreen) +{ + XUnmapWindow(nxagentDisplay, nxagentFullscreenWindow); + + if (nxagentIpaq) + { + XMapWindow(nxagentDisplay, nxagentIconWindow); + XIconifyWindow(nxagentDisplay, nxagentIconWindow, + DefaultScreen(nxagentDisplay)); + } + else + { + XIconifyWindow(nxagentDisplay, nxagentIconWindow, + DefaultScreen(nxagentDisplay)); + } +} + +void nxagentMaximizeToFullScreen(ScreenPtr pScreen) +{ + if (nxagentIpaq) + { + XUnmapWindow(nxagentDisplay, nxagentIconWindow); + + XMapWindow(nxagentDisplay, nxagentFullscreenWindow); + } + else + { +/* + XUnmapWindow(nxagentDisplay, nxagentIconWindow); +*/ +/* +FIXME: We'll check for ReparentNotify and LeaveNotify events after XReparentWindow() + in order to avoid the session window is iconified. + We could avoid the sesssion window is iconified when a LeaveNotify event is received, + so this check would be unnecessary. +*/ + struct timeval timeout; + int i; + XEvent e; + + XReparentWindow(nxagentDisplay, nxagentFullscreenWindow, + RootWindow(nxagentDisplay, DefaultScreen(nxagentDisplay)), 0, 0); + + for (i = 0; i < 100 && nxagentWMIsRunning; i++) + { + #ifdef TEST + fprintf(stderr, "nxagentMaximizeToFullscreen: WARNING! Going to wait for the ReparentNotify event.\n"); + #endif + + if (XCheckTypedWindowEvent(nxagentDisplay, nxagentFullscreenWindow, ReparentNotify, &e)) + { + break; + } + + XSync(nxagentDisplay, 0); + + timeout.tv_sec = 0; + timeout.tv_usec = 50 * 1000; + + nxagentWaitEvents(nxagentDisplay, &timeout); + } + + XMapRaised(nxagentDisplay, nxagentFullscreenWindow); + + XIconifyWindow(nxagentDisplay, nxagentIconWindow, + DefaultScreen(nxagentDisplay)); + + while (XCheckTypedWindowEvent(nxagentDisplay, nxagentFullscreenWindow, LeaveNotify, &e)); +/* + XMapWindow(nxagentDisplay, nxagentIconWindow); +*/ + } +} + +Window nxagentCreateIconWindow() +{ + XSetWindowAttributes attributes; + unsigned long valuemask; + char* window_name; + XTextProperty windowName; + XSizeHints sizeHints; + XWMHints wmHints; + Window w; + Mask mask; + + /* + * Create icon window. + */ + + attributes.override_redirect = False; + attributes.colormap = DefaultColormap(nxagentDisplay, DefaultScreen(nxagentDisplay)); + attributes.background_pixmap = nxagentScreenSaverPixmap; + valuemask = CWOverrideRedirect | CWBackPixmap | CWColormap; + + #ifdef TEST + fprintf(stderr, "nxagentCreateIconWindow: Going to create new icon window.\n"); + #endif + + w = XCreateWindow(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + 0, 0, 1, 1, 0, + DefaultDepth(nxagentDisplay, DefaultScreen(nxagentDisplay)), + InputOutput, + DefaultVisual(nxagentDisplay, DefaultScreen(nxagentDisplay)), + valuemask, &attributes); + + #ifdef TEST + fprintf(stderr, "nxagentCreateIconWindow: Created new icon window with id [%lu].\n", + (long unsigned int)nxagentIconWindow); + #endif + + /* + * Set hints to the window manager for the icon window. + */ + + window_name = nxagentWindowName; + XStringListToTextProperty(&window_name, 1, &windowName); + sizeHints.flags = PMinSize | PMaxSize; + sizeHints.min_width = sizeHints.max_width = 1; + sizeHints.min_height = sizeHints.max_height = 1; + wmHints.flags = IconPixmapHint | IconMaskHint; + wmHints.initial_state = IconicState; + wmHints.icon_pixmap = nxagentIconPixmap; + + if (useXpmIcon) + { + wmHints.icon_mask = nxagentIconShape; + wmHints.flags = IconPixmapHint | IconMaskHint; + } + else + { + wmHints.flags = StateHint | IconPixmapHint; + } + + XSetWMProperties(nxagentDisplay, w, + &windowName, &windowName, + NULL , 0 , &sizeHints, &wmHints, NULL); + + /* + * Enable events from the icon window. + */ + + nxagentGetDefaultEventMask(&mask); + + XSelectInput(nxagentDisplay, w, (mask & ~(KeyPressMask | + KeyReleaseMask)) | StructureNotifyMask); + + /* + * Notify to client if user closes icon window. + */ + + if (nxagentWMIsRunning && !nxagentOption(Rootless)) + { + XlibAtom deleteWMAtom = nxagentAtoms[2]; /* WM_DELETE_WINDOW */ + + XSetWMProtocols(nxagentDisplay, w, &deleteWMAtom, 1); + } + + return w; +} + +Bool nxagentMagicPixelZone(int x, int y) +{ + return (x >= nxagentOption(Width) - 1 && y < 1); +} + +void nxagentSetScreenSaverTime(void) +{ + #ifdef TEST + fprintf(stderr, "nxagentSetScreenSaverTime: ScreenSaverTime was [%lu], ScreenSaverInterval was [%lu].\n", + (long unsigned int)ScreenSaverTime, (long unsigned int)ScreenSaverInterval); + #endif + + /* + * More than one timeout could be used here, + * to make use of screen-saver handler not + * only for the timeout feature. In a case + * like this, the lower timeout have to be + * used as ScreenSaverTime. + */ + + if (nxagentAutoDisconnectTimeout > 0) + { + ScreenSaverTime = nxagentAutoDisconnectTimeout; + } + + ScreenSaverInterval = ScreenSaverTime; + + #ifdef TEST + fprintf(stderr, "nxagentSetScreenSaverTime: ScreenSaverTime now is [%lu], ScreenSaverInterval now is [%lu].\n", + (long unsigned int)ScreenSaverTime, (long unsigned int)ScreenSaverInterval); + #endif +} + +static Bool nxagentSaveScreen(ScreenPtr pScreen, int what) +{ + #ifdef TEST + fprintf(stderr, "nxagentSaveScreen: Called for screen at [%p] with parameter [%d].\n", + (void *) pScreen, what); + + fprintf(stderr, "nxagentSaveScreen: SCREEN_SAVER_ON is [%d] SCREEN_SAVER_OFF is [%d] " + "SCREEN_SAVER_FORCER is [%d] SCREEN_SAVER_CYCLE is [%d].\n", + SCREEN_SAVER_ON, SCREEN_SAVER_OFF, SCREEN_SAVER_FORCER, + SCREEN_SAVER_CYCLE); + #endif + + /* + * We need only to reset the timeouts + * in this case. + */ + + if (what == SCREEN_SAVER_OFF) + { + nxagentAutoDisconnectTimeout = nxagentOption(Timeout) * MILLI_PER_SECOND; + + return 1; + } + + /* + * The lastDeviceEventTime is updated every time + * a device event is received, and it is used by + * WaitForSomething() to know when the SaveScreens() + * function should be called. This solution doesn't + * take care of a pointer button not released, so + * we have to handle this case by ourselves. + */ + +/* +FIXME: Do we need to check the key grab if the + autorepeat feature is disabled? +*/ + if (inputInfo.pointer -> button -> buttonsDown > 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSaveScreen: Ignoring timeout, there is a pointer button down.\n"); + #endif + + /* + * Returning 0 the SaveScreens() function + * (which calls this one) tries to build + * a screen-saver creating a new window. + * We don't want this, so we return 1 in + * any case. + */ + + return 1; + } + + /* + * Handling the auto-disconnect feature. + * If there is any client attached and the persisten- + * ce is allowed then leave the session running, else + * terminate it. It should use something less brutal, + * though raising a signal should ensure that the code + * follows the usual execution path. + */ + + if (nxagentOption(Timeout) > 0) + { + #ifdef TEST + fprintf(stderr, "nxagentSaveScreen: Auto-disconnect timeout was [%d].\n", + nxagentAutoDisconnectTimeout); + #endif + + nxagentAutoDisconnectTimeout -= ScreenSaverTime; + + #ifdef TEST + fprintf(stderr, "nxagentSaveScreen: Auto-disconnect timeout is [%d].\n", + nxagentAutoDisconnectTimeout); + #endif + + if (nxagentSessionState == SESSION_UP && + nxagentAutoDisconnectTimeout <= 0) + { + nxagentAutoDisconnectTimeout = nxagentOption(Timeout) * MILLI_PER_SECOND; + + if (nxagentClients == 0) + { + fprintf(stderr, "Info: Terminating session with no client running.\n"); + + raise(SIGTERM); + } + else if (nxagentOption(Persistent) == 0) + { + fprintf(stderr, "Info: Terminating session with persistence not allowed.\n"); + + raise(SIGTERM); + } + else + { + fprintf(stderr, "Info: Suspending session with %d clients running.\n", + nxagentClients); + + raise(SIGHUP); + } + } + } + + return 1; +} + +Bool nxagentCreateScreenResources(ScreenPtr pScreen) +{ + Bool ret; + + CreatePixmapProcPtr savedCreatePixmap = pScreen->CreatePixmap; + ModifyPixmapHeaderProcPtr savedModifyPixmapHeader = pScreen->ModifyPixmapHeader; + + pScreen->CreatePixmap = fbCreatePixmap; + pScreen->ModifyPixmapHeader = miModifyPixmapHeader; + ret = miCreateScreenResources(pScreen); + + pScreen->CreatePixmap = savedCreatePixmap; + pScreen->ModifyPixmapHeader = savedModifyPixmapHeader; + + return ret; +} + +static Bool nxagentCursorOffScreen(ScreenPtr *pPtrScreen, int *x, int *y) +{ + return False; +} + +static void nxagentCrossScreen(ScreenPtr pScreen, Bool entering) +{ +} + +static miPointerScreenFuncRec nxagentPointerCursorFuncs = +{ + nxagentCursorOffScreen, + nxagentCrossScreen, + miPointerWarpCursor +}; + +#ifdef VIEWPORT_FRAME + +void nxagentInitViewportFrame(ScreenPtr pScreen, WindowPtr pRootWin) +{ + int error = Success; + VisualID visual = 0; + int i; + XID xid; + + if (nxagentOption(Rootless)) + { + return; + } + + for (i = 0; i < pScreen -> numDepths; i++) + { + if (pScreen -> allowedDepths[i].depth == pRootWin -> drawable.depth) + { + visual = pScreen -> allowedDepths[i].vids[0]; + break; + } + } + + /* + * It is not necessary create the windows on the real X server. But this + * windows are not visible. Create them it is not a great effort, and avoids + * many errors. + * + * nxagentScreenTrap = True; + */ + + xid = FakeClientID(serverClient -> index); + + #ifdef TEST + fprintf(stderr, "nxagentInitViewportFrame: XID = [%lx]\n", xid); + #endif + + nxagentViewportFrameLeft = CreateWindow(xid, pRootWin, -NXAGENT_FRAME_WIDTH, 0, NXAGENT_FRAME_WIDTH, + pRootWin -> drawable.height, + 0, InputOutput, 0, NULL, + pRootWin -> drawable.depth, + serverClient, visual, &error); + + AddResource(xid, RT_WINDOW, (void *) nxagentViewportFrameLeft); + + if (error != Success) + { + #ifdef WARNING + fprintf(stderr, "nxagentInitViewportFrame: Error creating nxagentViewportFrameLeft.\n"); + #endif + + error = Success; + } + + xid = FakeClientID(serverClient -> index); + + #ifdef TEST + fprintf(stderr, "nxagentInitViewportFrame: XID = [%lx]\n", xid); + #endif + + nxagentViewportFrameRight = CreateWindow(xid, pRootWin, pRootWin -> drawable.width, 0, + NXAGENT_FRAME_WIDTH, + pRootWin -> drawable.height, + 0, InputOutput, 0, NULL, + pRootWin -> drawable.depth, + serverClient, visual, + &error); + + AddResource(xid, RT_WINDOW, (void *) nxagentViewportFrameRight); + + if (error != Success) + { + #ifdef WARNING + fprintf(stderr, "nxagentInitViewportFrame: Error creating nxagentViewportFrameRight.\n"); + #endif + + error = Success; + } + + xid = FakeClientID(serverClient -> index); + + #ifdef TEST + fprintf(stderr, "nxagentInitViewportFrame: XID = [%lx]\n", xid); + #endif + + nxagentViewportFrameAbove = CreateWindow(xid, pRootWin, 0, -NXAGENT_FRAME_WIDTH, + pRootWin -> drawable.width, + NXAGENT_FRAME_WIDTH, 0, + InputOutput, 0, NULL, + pRootWin -> drawable.depth, + serverClient, visual, + &error); + + AddResource(xid, RT_WINDOW, (void *) nxagentViewportFrameAbove); + + if (error != Success) + { + #ifdef WARNING + fprintf(stderr, "nxagentInitViewportFrame: Error creating nxagentViewportFrameAbove.\n"); + #endif + + error = Success; + } + + xid = FakeClientID(serverClient -> index); + + #ifdef TEST + fprintf(stderr, "nxagentInitViewportFrame: XID = [%lx]\n", xid); + #endif + + nxagentViewportFrameBelow = CreateWindow(xid, pRootWin, 0, + pRootWin -> drawable.height, + pRootWin -> drawable.width, + NXAGENT_FRAME_WIDTH, 0, + InputOutput, 0, NULL, + pRootWin -> drawable.depth, + serverClient, visual, &error); + + AddResource(xid, RT_WINDOW, (void *) nxagentViewportFrameBelow); + + if (error != Success) + { + #ifdef WARNING + fprintf(stderr, "nxagentInitViewportFrame: Error creating nxagentViewportFrameBelow.\n"); + #endif + } + + nxagentViewportFrameLeft -> overrideRedirect = 1; + nxagentViewportFrameRight -> overrideRedirect = 1; + nxagentViewportFrameAbove -> overrideRedirect = 1; + nxagentViewportFrameBelow -> overrideRedirect = 1; + + MapWindow(nxagentViewportFrameLeft, serverClient); + MapWindow(nxagentViewportFrameRight, serverClient); + MapWindow(nxagentViewportFrameAbove, serverClient); + MapWindow(nxagentViewportFrameBelow, serverClient); + + /* + * nxagentScreenTrap = False; + */ +} + +#endif /* #ifdef VIEWPORT_FRAME */ + +void nxagentPrintAgentGeometry(char *hdrMessage, char *prefix) +{ + #ifdef WARNING + + if (prefix == NULL) + { + prefix = ""; + } + + if (hdrMessage) + { + fprintf(stderr, "--------------- %s -----------------.\n", hdrMessage); + } + + fprintf(stderr, "%s Root window at offset (%d,%d) size (%d,%d).\n", prefix, + nxagentOption(RootX), nxagentOption(RootY), + nxagentOption(RootWidth), nxagentOption(RootHeight)); + + fprintf(stderr, "%s Default window at offset (%d,%d) size (%d,%d) border size %d.\n", prefix, + nxagentOption(X), nxagentOption(Y), nxagentOption(Width), nxagentOption(Height), + nxagentOption(BorderWidth)); + + fprintf(stderr, "%s Span between root window and default window is (%d,%d).\n", prefix, + nxagentOption(ViewportXSpan), nxagentOption(ViewportYSpan)); + + fprintf(stderr, "%s Default window in window mode has offset (%d,%d) and size (%d,%d).\n", prefix, + nxagentOption(SavedX), nxagentOption(SavedY), nxagentOption(SavedWidth), nxagentOption(SavedHeight)); + + fprintf(stderr, "%s Fullscreen is %s.\n", prefix, + nxagentOption(Fullscreen) ? "ON" : "OFF"); + + fprintf(stderr, "%s Desktop resize mode is %s.\n", prefix, + nxagentOption(DesktopResize) ? "ON" : "OFF"); + + fprintf(stderr, "%s Resize desktop at startup is %s.\n", prefix, + nxagentResizeDesktopAtStartup ? "ON" : "OFF"); + + #endif +} + +static int nxagentColorOffset(unsigned long mask) +{ + int count; + + for (count = 0; !(mask & 1) && count < 32; count++) + { + mask >>= 1; + } + + return count; +} + +Bool nxagentOpenScreen(ScreenPtr pScreen, + int argc, char *argv[]) +{ + VisualPtr visuals; + DepthPtr depths; + int numVisuals, numDepths; + int i, j, depthIndex; + unsigned long valuemask; + XSetWindowAttributes attributes; + XWindowAttributes gattributes; + XSizeHints sizeHints; + XWMHints wmHints; + Mask mask; + Bool resetAgentPosition = False; + + VisualID defaultVisual; + int rootDepth; + + void * pFrameBufferBits; + int bitsPerPixel; + int sizeInBytes; + + int defaultVisualIndex = 0; + + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Called for screen index [%d].\n", + pScreen->myNum); + #endif + + if (nxagentRenderEnable && nxagentReconnectTrap == False) + { + PictureScreenPrivateIndex = -1; + } + + nxagentDefaultScreen = pScreen; + + nxagentQueryAtoms(pScreen); + + #ifdef NXAGENT_ONSTART + nxagentWMStart = nxagentAtoms[3]; /* WM_NX_READY */ + #endif + + /* + * Forced geometry parameter + * to user geometry. + */ + + if (nxagentResizeDesktopAtStartup) + { + if (nxagentUserGeometry.flag & XValue) + { + nxagentChangeOption(X, nxagentUserGeometry.X); + } + + if (nxagentUserGeometry.flag & YValue) + { + nxagentChangeOption(Y, nxagentUserGeometry.Y); + } + + if (nxagentUserGeometry.flag & WidthValue) + { + nxagentChangeOption(Width, nxagentUserGeometry.Width); + nxagentChangeOption(RootWidth, nxagentUserGeometry.Width); + + if (nxagentOption(SavedWidth) > nxagentUserGeometry.Width) + { + nxagentChangeOption(SavedWidth, nxagentUserGeometry.Width); + } + } + + if (nxagentUserGeometry.flag & HeightValue) + { + nxagentChangeOption(Height, nxagentUserGeometry.Height); + nxagentChangeOption(RootHeight, nxagentUserGeometry.Height); + + if (nxagentOption(SavedHeight) > nxagentUserGeometry.Height) + { + nxagentChangeOption(SavedHeight, nxagentUserGeometry.Height); + } + } + } + + /* + * This is first time the + * screen is initialized. + * Filling the geometry parameter + * from user geometry. + */ + + if (nxagentReconnectTrap == False) + { + if (nxagentUserGeometry.flag & XValue) + { + nxagentChangeOption(X, nxagentUserGeometry.X); + } + + if (nxagentUserGeometry.flag & YValue) + { + nxagentChangeOption(Y, nxagentUserGeometry.Y); + } + + if (nxagentUserGeometry.flag & WidthValue) + { + nxagentChangeOption(RootWidth, nxagentUserGeometry.Width); + } + + if (nxagentUserGeometry.flag & HeightValue) + { + nxagentChangeOption(RootHeight, nxagentUserGeometry.Height); + } + } + else if (nxagentWMIsRunning && !nxagentOption(Rootless) && !nxagentOption(Fullscreen)) + { + /* + * At reconnection, try to estimate the shift due to WM reparenting. + */ + + if (nxagentOption(X) >= 6) + { + nxagentChangeOption(X, nxagentOption(X) - 6); + } + + if (nxagentOption(Y) >= 25) + { + nxagentChangeOption(Y, nxagentOption(Y) - 25); + } + } + + /* + * Determine the size of the root window. + * It is the maximum size of the screen + * if we are either in rootless or in + * fullscreen mode. + */ + + if (nxagentOption(Rootless) == False && nxagentWMIsRunning == False) + { + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Forcing fullscreen mode with no window manager running.\n"); + #endif + + nxagentChangeOption(Fullscreen, True); + + if (nxagentOption(ClientOs) == ClientOsWinnt && + (nxagentReconnectTrap == False || nxagentResizeDesktopAtStartup)) + { + NXSetExposeParameters(nxagentDisplay, 0, 0, 0); + } + } + + if (nxagentOption(Fullscreen) && + nxagentWMIsRunning && + nxagentReconnectTrap && + nxagentResizeDesktopAtStartup == False && + nxagentXServerGeometryChanged()) + { + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Forcing window mode with server geometry changed.\n"); + #endif + + nxagentChangeOption(Fullscreen, False); + + nxagentChangeOption(AllScreens, False); + + nxagentFullscreenWindow = 0; + + resetAgentPosition = True; + } + + if (nxagentOption(Fullscreen)) + { + nxagentChangeOption(X, 0); + nxagentChangeOption(Y, 0); + + nxagentChangeOption(Width, WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay))); + nxagentChangeOption(Height, HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay))); + + nxagentChangeOption(BorderWidth, 0); + + if (nxagentReconnectTrap == False || nxagentResizeDesktopAtStartup) + { + nxagentChangeOption(RootWidth, WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay))); + nxagentChangeOption(RootHeight, HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay))); + + if (nxagentOption(RootWidth) > WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay))) + { + nxagentChangeOption(SavedWidth, WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) * 3 / 4); + } + else + { + nxagentChangeOption(SavedWidth, nxagentOption(RootWidth)); + } + + if (nxagentOption(RootHeight) > HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay))) + { + nxagentChangeOption(SavedHeight, HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) * 3 / 4); + } + else + { + nxagentChangeOption(SavedHeight, nxagentOption(RootHeight)); + } + } + + nxagentChangeOption(RootX, ((WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) - + nxagentOption(RootWidth)) / 2)); + nxagentChangeOption(RootY, ((HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) - + nxagentOption(RootHeight)) / 2)); + } + else + { + nxagentChangeOption(BorderWidth, 0); + + if (nxagentReconnectTrap == False) + { + nxagentChangeOption(RootX, 0); + nxagentChangeOption(RootY, 0); + + nxagentChangeOption(Width, nxagentOption(RootWidth)); + nxagentChangeOption(Height, nxagentOption(RootHeight)); + } + + /* + * Be sure that the agent window won't be bigger + * than the root window. + */ + + if (nxagentOption(Width) > nxagentOption(RootWidth)) + { + nxagentChangeOption(Width, nxagentOption(RootWidth)); + } + + if (nxagentOption(Height) > nxagentOption(RootHeight)) + { + nxagentChangeOption(Height, nxagentOption(RootHeight)); + } + + /* + * Be sure that the agent window won't be bigger + * than the X server root window. + */ + + if (nxagentOption(Width) > WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay))) + { + nxagentChangeOption(Width, WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) * 3 / 4); + } + + if (nxagentOption(Height) > HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay))) + { + nxagentChangeOption(Height, HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) * 3 / 4); + } + + /* + * Forcing the agent window geometry to be equal to + * the root window geometry the first time the + * screen is initialized if the geometry hasn't been + * esplicitly set in the option file and if + * the root window isn't bigger than the X server + * root window.. + */ + + if (nxagentReconnectTrap == False) + { + if ((nxagentOption(RootWidth) < WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay))) && + !(nxagentUserGeometry.flag & WidthValue)) + { + nxagentChangeOption(Width, nxagentOption(RootWidth)); + } + + if ((nxagentOption(RootHeight) < HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay))) && + !(nxagentUserGeometry.flag & HeightValue)) + { + nxagentChangeOption(Height, nxagentOption(RootHeight)); + } + } + + if (resetAgentPosition) + { + nxagentChangeOption(X, ((WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) - + nxagentOption(Width)) / 2)); + + nxagentChangeOption(Y, ((HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) - + nxagentOption(Height)) / 2)); + } + + nxagentChangeOption(SavedWidth, nxagentOption(RootWidth)); + nxagentChangeOption(SavedHeight, nxagentOption(RootHeight)); + } + + if (nxagentOption(Rootless)) + { + nxagentChangeOption(RootWidth, WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay))); + nxagentChangeOption(RootHeight, HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay))); + } + + nxagentChangeOption(SavedRootWidth, nxagentOption(RootWidth)); + nxagentChangeOption(SavedRootHeight, nxagentOption(RootHeight)); + + nxagentChangeOption(ViewportXSpan, nxagentOption(Width) - nxagentOption(RootWidth)); + nxagentChangeOption(ViewportYSpan, nxagentOption(Height) - nxagentOption(RootHeight)); + + if (nxagentReconnectTrap == 0) + { + if (nxagentOption(Persistent)) + { + nxagentArgc = argc; + nxagentArgv = argv; + } + + #ifdef NXAGENT_TIMESTAMP + + { + extern unsigned long startTime; + + fprintf(stderr, "Screen: going to open screen, time is [%d] milliseconds.\n", + GetTimeInMillis() - startTime); + } + + #endif + + /* + * Initialize all our privates. + */ + + if (AllocateWindowPrivate(pScreen, nxagentWindowPrivateIndex, sizeof(nxagentPrivWindowRec)) == 0 || + AllocateGCPrivate(pScreen, nxagentGCPrivateIndex, sizeof(nxagentPrivGC)) == 0 || + AllocateClientPrivate(nxagentClientPrivateIndex, sizeof(PrivClientRec)) == 0 || + AllocatePixmapPrivate(pScreen, nxagentPixmapPrivateIndex, sizeof(nxagentPrivPixmapRec)) == 0) + { + return False; + } + + /* + * Initialize the depths. + */ + + depths = (DepthPtr) malloc(nxagentNumDepths * sizeof(DepthRec)); + + for (i = 0; i < nxagentNumDepths; i++) + { + depths[i].depth = nxagentDepths[i]; + depths[i].numVids = 0; + depths[i].vids = (VisualID *) malloc(MAXVISUALSPERDEPTH * sizeof(VisualID)); + } + + /* + * Initialize the visuals. + */ + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "Debug: Setting up visuals. Original array has size " + "[%d].\n", nxagentNumVisuals); + #endif + + numVisuals = 0; + numDepths = nxagentNumDepths; + + visuals = (VisualPtr) malloc(nxagentNumVisuals * sizeof(VisualRec)); + + for (i = 0; i < nxagentNumVisuals; i++) + { + visuals[numVisuals].vid = FakeClientID(0); + visuals[numVisuals].class = nxagentVisuals[i].class; + visuals[numVisuals].bitsPerRGBValue = nxagentVisuals[i].bits_per_rgb; + visuals[numVisuals].ColormapEntries = nxagentVisuals[i].colormap_size; + visuals[numVisuals].nplanes = nxagentVisuals[i].depth; + visuals[numVisuals].redMask = nxagentVisuals[i].red_mask; + visuals[numVisuals].greenMask = nxagentVisuals[i].green_mask; + visuals[numVisuals].blueMask = nxagentVisuals[i].blue_mask; + visuals[numVisuals].offsetRed = nxagentColorOffset(nxagentVisuals[i].red_mask); + visuals[numVisuals].offsetGreen = nxagentColorOffset(nxagentVisuals[i].green_mask); + visuals[numVisuals].offsetBlue = nxagentColorOffset(nxagentVisuals[i].blue_mask); + + /* + * Check for and remove the duplicates. + */ + + if (i == nxagentDefaultVisualIndex) + { + defaultVisualIndex = numVisuals; + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "Debug: Set default visual index [%d].\n" , + defaultVisualIndex); + #endif + } + else + { + for (j = 0; j < numVisuals; j++) + { + if (visuals[numVisuals].class == visuals[j].class && + visuals[numVisuals].bitsPerRGBValue == + visuals[j].bitsPerRGBValue && + visuals[numVisuals].ColormapEntries == + visuals[j].ColormapEntries && + visuals[numVisuals].nplanes == visuals[j].nplanes && + visuals[numVisuals].redMask == visuals[j].redMask && + visuals[numVisuals].greenMask == visuals[j].greenMask && + visuals[numVisuals].blueMask == visuals[j].blueMask && + visuals[numVisuals].offsetRed == visuals[j].offsetRed && + visuals[numVisuals].offsetGreen == visuals[j].offsetGreen && + visuals[numVisuals].offsetBlue == visuals[j].offsetBlue) + break; + } + + if (j < numVisuals) + continue; + + } + + depthIndex = UNDEFINED; + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "Debug: Added visual [%lu].\n" , + (long unsigned int)visuals[numVisuals].vid); + #endif + + for (j = 0; j < numDepths; j++) + { + if (depths[j].depth == nxagentVisuals[i].depth) + { + depthIndex = j; + break; + } + } + + if (depthIndex == UNDEFINED) + { + #ifdef WARNING + fprintf(stderr, "nxagentOpenScreen: WARNING! Can't find a matching depth for visual depth [%d].\n", + nxagentVisuals[i].depth); + #endif + + depthIndex = numDepths; + + depths[depthIndex].depth = nxagentVisuals[i].depth; + depths[depthIndex].numVids = 0; + depths[depthIndex].vids = (VisualID *) malloc(MAXVISUALSPERDEPTH * sizeof(VisualID)); + + numDepths++; + } + + if (depths[depthIndex].numVids >= MAXVISUALSPERDEPTH) + { + FatalError("Visual table overflow"); + } + + depths[depthIndex].vids[depths[depthIndex].numVids] = visuals[numVisuals].vid; + + depths[depthIndex].numVids++; + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "Debug: Registered visual [%lu] for depth [%d (%d)].\n" , + (long unsigned int)visuals[numVisuals].vid, depthIndex, + depths[depthIndex].depth); + #endif + + numVisuals++; + } + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "Debug: Setting default visual [%d (%lu)].\n", + defaultVisualIndex, (long unsigned int)visuals[defaultVisualIndex].vid); + + fprintf(stderr, "Debug: Setting root depth [%d].\n", + visuals[defaultVisualIndex].nplanes); + #endif + + defaultVisual = visuals[defaultVisualIndex].vid; + rootDepth = visuals[defaultVisualIndex].nplanes; + + nxagentInitAlphaVisual(); + + bitsPerPixel = nxagentBitsPerPixel(rootDepth); + + if (bitsPerPixel == 1) + { + sizeInBytes = PixmapBytePad(nxagentOption(RootWidth), rootDepth) * nxagentOption(RootHeight); + } + else + { + sizeInBytes = PixmapBytePad(nxagentOption(RootWidth), rootDepth) * nxagentOption(RootHeight) * bitsPerPixel/8; + } + + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Frame buffer allocated. rootDepth " + "[%d] bitsPerPixel [%d] sizeInBytes [%d]\n", rootDepth, bitsPerPixel, sizeInBytes); + #endif + + pFrameBufferBits = (char *) malloc(sizeInBytes); + + if (!pFrameBufferBits) + { + return FALSE; + } + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "nxagentOpenScreen: Before fbScreenInit numVisuals [%d] numDepths [%d] " + "rootDepth [%d] defaultVisual [%lu].\n", numVisuals, numDepths, + rootDepth, (long unsigned int)defaultVisual); + #endif + + if (monitorResolution < 1) + { + monitorResolution = NXAGENT_DEFAULT_DPI; + } + + if (!fbScreenInit(pScreen, pFrameBufferBits, nxagentOption(RootWidth), nxagentOption(RootHeight), + monitorResolution, monitorResolution, PixmapBytePad(nxagentOption(RootWidth), rootDepth), bitsPerPixel)) + { + return FALSE; + } + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "nxagentOpenScreen: After fbScreenInit numVisuals [%d] numDepths [%d] " + "rootDepth [%d] defaultVisual [%lu].\n", numVisuals, numDepths, + rootDepth, (long unsigned int)defaultVisual); + #endif + + /* + * Complete the initialization of the GLX + * extension. This will add the GLX visuals + * and will modify numVisuals and numDepths. + */ + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "nxagentOpenScreen: Before GLX numVisuals [%d] numDepths [%d] " + "rootDepth [%d] defaultVisual [%lu].\n", numVisuals, numDepths, + rootDepth, (long unsigned int)defaultVisual); + #endif + + nxagentInitGlxExtension(&visuals, &depths, &numVisuals, &numDepths, + &rootDepth, &defaultVisual); + + #if defined(DEBUG) || defined(DEBUG_COLORMAP) + fprintf(stderr, "nxagentOpenScreen: After GLX numVisuals [%d] numDepths [%d] " + "rootDepth [%d] defaultVisual [%lu].\n", numVisuals, numDepths, + rootDepth, (long unsigned int)defaultVisual); + #endif + + /* + * Replace the visuals and depths initialized + * by fbScreenInit with our own. + */ + + free(pScreen -> visuals); + free(pScreen -> allowedDepths); + + pScreen -> visuals = visuals; + pScreen -> allowedDepths = depths; + pScreen -> numVisuals = numVisuals; + pScreen -> numDepths = numDepths; + pScreen -> rootVisual = defaultVisual; + pScreen -> rootDepth = rootDepth; + + /* + * Complete the initialization of the RANDR + * extension. + */ + + nxagentInitRandRExtension(pScreen); + + /* + * Set up the internal structures used for + * tracking the proxy resources associated + * to the unpack and split operations. + */ + + nxagentInitSplitResources(); + nxagentInitUnpackResources(); + + /* + * Initializing the pixmaps that will serve as + * "placeholders" in lazy encoding. We need one + * pixmap for each depth. + */ + + for (i = 0; i < numDepths; i++) + { + nxagentMarkPlaceholderNotLoaded(i); + } + + #ifdef WATCH + + fprintf(stderr, "nxagentOpenScreen: Watchpoint 7.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +N/A +*/ + + sleep(30); + + #endif + + if (nxagentParentWindow != 0) + { + /* + * This would cause a GetWindowAttributes + * and a GetGeometry (asynchronous) reply. + */ + + XGetWindowAttributes(nxagentDisplay, nxagentParentWindow, &gattributes); + + nxagentChangeOption(Width, gattributes.width); + nxagentChangeOption(Height, gattributes.height); + } + + if (nxagentOption(AllScreens)) + { + attributes.override_redirect = True; + } + + if (nxagentOption(Fullscreen)) + { + /* + * We need to disable the host's screensaver or + * it will otherwise grab the screen even if it + * is under agent's control. + */ + + XSetScreenSaver(nxagentDisplay, 0, 0, DefaultExposures, DefaultBlanking); + } + + if (nxagentTrue24) + { + fbGetScreenPrivate(pScreen) -> win32bpp = visuals[nxagentDefaultVisualIndex].nplanes; + fbGetScreenPrivate(pScreen) -> pix32bpp = visuals[nxagentDefaultVisualIndex].nplanes; + } + else + { + fbGetScreenPrivate(pScreen) -> win32bpp = 32; + fbGetScreenPrivate(pScreen) -> pix32bpp = 32; + } + + /* + * We call miScreenInit with NULL in place of the screen area if we + * don't want to initialize the frame buffer. + * + * if (!miScreenInit(pScreen, NULL, nxagentOption(RootWidth), + * nxagentOption(RootHeight), 1, 1, nxagentOption(RootWidth), + * visuals[nxagentDefaultVisualIndex].nplanes, / * Root depth. * / + * numDepths, depths, + * visuals[nxagentDefaultVisualIndex].vid,* Root visual. * / + * numVisuals, visuals)) + * return FALSE; + */ + + pScreen->defColormap = (Colormap) FakeClientID(0); + pScreen->minInstalledCmaps = MINCMAPS; + pScreen->maxInstalledCmaps = MAXCMAPS; + + pScreen->whitePixel = nxagentWhitePixel; + pScreen->blackPixel = nxagentBlackPixel; + /* rgf */ + /* GCperDepth */ + /* PixmapPerDepth */ + /* WindowPrivateLen */ + /* WindowPrivateSizes */ + /* totalWindowSize */ + /* GCPrivateLen */ + /* GCPrivateSizes */ + /* totalGCSize */ + + /* + * Random screen procedures. + */ + + pScreen->CloseScreen = nxagentCloseScreen; + pScreen->QueryBestSize = nxagentQueryBestSize; + pScreen->SaveScreen = nxagentSaveScreen; + pScreen->GetImage = nxagentGetImage; + pScreen->GetSpans = nxagentGetSpans; + pScreen->PointerNonInterestBox = (void (*)()) 0; + pScreen->SourceValidate = (void (*)()) 0; + + pScreen->CreateScreenResources = nxagentCreateScreenResources; + + /* + * Window Procedures. + * + * Note that the following functions are not + * replaced with nxagent counterparts: + * + * ValidateTreeProcPtr ValidateTree; + * ClearToBackgroundProcPtr ClearToBackground; + * + * Note also that the ConfigureWindow procedure + * has not a pointer in the screen structure. + */ + + pScreen->CreateWindow = nxagentCreateWindow; + pScreen->DestroyWindow = nxagentDestroyWindow; + pScreen->PositionWindow = nxagentPositionWindow; + pScreen->ChangeWindowAttributes = nxagentChangeWindowAttributes; + pScreen->RealizeWindow = nxagentRealizeWindow; + pScreen->UnrealizeWindow = nxagentUnrealizeWindow; + pScreen->PostValidateTree = nxagentPostValidateTree; + pScreen->WindowExposures = nxagentWindowExposures; + pScreen->PaintWindowBackground = nxagentPaintWindowBackground; + pScreen->PaintWindowBorder = nxagentPaintWindowBorder; + pScreen->CopyWindow = nxagentCopyWindow; + pScreen->ClipNotify = nxagentClipNotify; + pScreen->RestackWindow = nxagentRestackWindow; + pScreen->ReparentWindow = nxagentReparentWindow; + + /* + * Pixmap procedures. + */ + + pScreen->CreatePixmap = nxagentCreatePixmap; + pScreen->DestroyPixmap = nxagentDestroyPixmap; + + /* + * This is originally miModifyPixmapHeader() + * from miscrinit.c. It is used to recycle + * the scratch pixmap for this screen. + */ + + pScreen->ModifyPixmapHeader = nxagentModifyPixmapHeader; + + /* + * Font procedures. + */ + + pScreen->RealizeFont = nxagentRealizeFont; + pScreen->UnrealizeFont = nxagentUnrealizeFont; + + /* + * GC procedures. + */ + + pScreen->CreateGC = nxagentCreateGC; + pScreen->BitmapToRegion = nxagentPixmapToRegion; + + /* + * Colormap procedures. + */ + + pScreen->CreateColormap = nxagentCreateColormap; + pScreen->DestroyColormap = nxagentDestroyColormap; + pScreen->InstallColormap = nxagentInstallColormap; + pScreen->UninstallColormap = nxagentUninstallColormap; + pScreen->ListInstalledColormaps = nxagentListInstalledColormaps; + pScreen->StoreColors = nxagentStoreColors; + pScreen->ResolveColor = nxagentResolveColor; + + /* + * Backing store procedures. + */ + + pScreen->SaveDoomedAreas = (void (*)()) 0; + pScreen->RestoreAreas = (RegionPtr (*)()) 0; + pScreen->ExposeCopy = (void (*)()) 0; + pScreen->TranslateBackingStore = (RegionPtr (*)()) 0; + pScreen->ClearBackingStore = (RegionPtr (*)()) 0; + pScreen->DrawGuarantee = (void (*)()) 0; + + if (enableBackingStore == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Going to initialize backing store.\n"); + #endif + + pScreen -> BackingStoreFuncs.SaveAreas = nxagentSaveAreas; + pScreen -> BackingStoreFuncs.RestoreAreas = nxagentRestoreAreas; + pScreen -> BackingStoreFuncs.SetClipmaskRgn = 0; + pScreen -> BackingStoreFuncs.GetImagePixmap = 0; + pScreen -> BackingStoreFuncs.GetSpansPixmap = 0; + + miInitializeBackingStore(pScreen); + } + + /* + * OS layer procedures. + */ + + pScreen->BlockHandler = (ScreenBlockHandlerProcPtr) NoopDDA; + pScreen->WakeupHandler = (ScreenWakeupHandlerProcPtr) NoopDDA; + pScreen->blockData = NULL; + pScreen->wakeupData = NULL; + + #ifdef RENDER + + /* + * Initialize picture support. This have to be + * placed here because miDCInitialize calls + * DamageSetup, that should wrap the picture + * screen functions. So PictureInit has to be + * called before. + */ + + if (nxagentRenderEnable && !nxagentReconnectTrap) + { + if (!nxagentPictureInit(pScreen, 0, 0)) + { + nxagentRenderEnable = False; + + return FALSE; + } + + if (nxagentAlphaEnabled) + { + fprintf(stderr, "Info: Using alpha channel in render extension.\n"); + } + } + + #endif /* RENDER */ + + /* + * From misprite.c: called from device-dependent screen + * initialization proc after all of the function pointers + * have been stored in the screen structure. + */ + + miDCInitialize(pScreen, &nxagentPointerCursorFuncs); + + /* + * Cursor Procedures. + */ + + pScreen->ConstrainCursor = nxagentConstrainCursor; + pScreen->CursorLimits = nxagentCursorLimits; + pScreen->DisplayCursor = nxagentDisplayCursor; + pScreen->RealizeCursor = nxagentRealizeCursor; + pScreen->UnrealizeCursor = nxagentUnrealizeCursor; + pScreen->RecolorCursor = nxagentRecolorCursor; + + nxagentSetCursorPositionW = pScreen->SetCursorPosition; + + pScreen->SetCursorPosition = nxagentSetCursorPosition; + + #define POSITION_OFFSET (pScreen->myNum * (nxagentOption(Width) + \ + nxagentOption(Height)) / 32) + } + + #ifdef TEST + nxagentPrintAgentGeometry(NULL, "nxagentOpenScreen:"); + #endif + + if (nxagentDoFullGeneration == 1 || + nxagentReconnectTrap == 1) + { + valuemask = CWBackPixel | CWEventMask | CWColormap | + (nxagentOption(AllScreens) == 1 ? CWOverrideRedirect : 0); + + attributes.background_pixel = nxagentBlackPixel; + + /* Assume that the mask fits in int... broken on Big Endian 64bit systems. */ + Mask tmp_mask = attributes.event_mask; + nxagentGetDefaultEventMask(&tmp_mask); + attributes.event_mask = (int)tmp_mask; + + attributes.colormap = nxagentDefaultVisualColormap(nxagentDefaultVisual(pScreen)); + + if (nxagentOption(AllScreens) == 1) + { + attributes.override_redirect = True; + } + + if (nxagentOption(Fullscreen) == 1) + { + if (nxagentReconnectTrap) + { + /* + * We need to disable the host's screensaver or + * it will otherwise grab the screen even if it + * is under agent's control. + */ + + XSetScreenSaver(nxagentDisplay, 0, 0, DefaultExposures, DefaultBlanking); + } + } + + /* + * This would be used when running agent + * embedded into another X window. + */ + + if (nxagentParentWindow != 0) + { + nxagentDefaultWindows[pScreen->myNum] = nxagentParentWindow; + + nxagentGetDefaultEventMask(&mask); + + XSelectInput(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], mask); + } + else + { + /* + * Create any top-level window as a child of the + * real root of the remote display. See also the + * InitRootWindow() procedure and the function + * handling the splash screen. + */ + + if (nxagentOption(Rootless) == True) + { + nxagentDefaultWindows[pScreen->myNum] = DefaultRootWindow(nxagentDisplay); + + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Using root window id [%ld].\n", + (long int)nxagentDefaultWindows[pScreen->myNum]); + #endif + } + + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Going to create new default window.\n"); + #endif + + nxagentDefaultWindows[pScreen->myNum] = + XCreateWindow(nxagentDisplay, + DefaultRootWindow(nxagentDisplay), + nxagentOption(X) + POSITION_OFFSET, + nxagentOption(Y) + POSITION_OFFSET, + nxagentOption(Width), + nxagentOption(Height), + nxagentOption(BorderWidth), + pScreen->rootDepth, + InputOutput, + nxagentDefaultVisual(pScreen), + valuemask, &attributes); + + if (nxagentOption(Rootless) == 0) + { + valuemask = CWEventMask; + mask = PointerMotionMask; + attributes.event_mask = mask; + + nxagentInputWindows[pScreen -> myNum] = + XCreateWindow(nxagentDisplay, + nxagentDefaultWindows[pScreen -> myNum], + 0, 0, + nxagentOption(Width), + nxagentOption(Height), + 0, 0, InputOnly, + nxagentDefaultVisual(pScreen), + valuemask , &attributes); + } + + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Created new default window with id [%ld].\n", + (long int)nxagentDefaultWindows[pScreen->myNum]); + #endif + + /* + * Setting WM_CLASS to "X2GoAgent" when running in X2Go Agent mode + * we need it to properly display all window parameters by some WMs + * (for example on Maemo) + */ + if(nxagentX2go) + { + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Setting WM_CLASS and WM_NAME for window withid [%ld].\n", + (long int)nxagentDefaultWindows[pScreen->myNum]); + #endif + XClassHint hint; + hint.res_name=malloc(strlen("X2GoAgent")+1); + hint.res_class=malloc(strlen("X2GoAgent")+1); + strcpy(hint.res_name,"X2GoAgent"); + strcpy(hint.res_class,"X2GoAgent"); + XSetClassHint(nxagentDisplay,nxagentDefaultWindows[pScreen->myNum],&hint); + free(hint.res_name); + free(hint.res_class); + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Setting WM_CLASS and WM_NAME for window withid [%ld].\n", + (long int)nxagentDefaultWindows[pScreen->myNum]); + #endif + + XClassHint hint; + hint.res_name=malloc(strlen("NXAgent")+1); + hint.res_class=malloc(strlen("NXAgent")+1); + strcpy(hint.res_name,"NXAgent"); + strcpy(hint.res_class,"NXAgent"); + XSetClassHint(nxagentDisplay,nxagentDefaultWindows[pScreen->myNum],&hint); + free(hint.res_name); + free(hint.res_class); + } + + + if (nxagentOption(Fullscreen)) + { + nxagentFullscreenWindow = nxagentDefaultWindows[pScreen->myNum]; + } + + if (nxagentIpaq) + { + XWindowChanges ch; + unsigned int ch_mask; + + ch.stack_mode = Below; + ch_mask = CWStackMode; + + XConfigureWindow(nxagentDisplay, nxagentFullscreenWindow, ch_mask, &ch); + } + } + + if (nxagentOption(Fullscreen)) + { + /* + * FIXME: Do we still need to set this property? + */ + + if (nxagentAtoms[8] != 0) + { + XChangeProperty(nxagentDisplay, + nxagentDefaultWindows[pScreen->myNum], + nxagentAtoms[8], /* NX_AGENT_SIGNATURE */ + XA_STRING, + 8, + PropModeReplace, + (unsigned char*) "X-AGENT", + strlen("X-AGENT")); + } + + nxagentGetDefaultEventMask(&mask); + + XSelectInput(nxagentDisplay, nxagentFullscreenWindow, mask); + } + + sizeHints.flags = PPosition | PMinSize | PMaxSize; + sizeHints.x = nxagentOption(X) + POSITION_OFFSET; + sizeHints.y = nxagentOption(Y) + POSITION_OFFSET; + sizeHints.min_width = MIN_NXAGENT_WIDTH; + sizeHints.min_height = MIN_NXAGENT_HEIGHT; + + sizeHints.width = nxagentOption(RootWidth); + sizeHints.height = nxagentOption(RootHeight); + + if (nxagentOption(DesktopResize) == 1 || nxagentOption(Fullscreen) == 1) + { + sizeHints.max_width = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + sizeHints.max_height = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + } + else + { + sizeHints.max_width = nxagentOption(RootWidth); + sizeHints.max_height = nxagentOption(RootHeight); + } + + if (nxagentUserGeometry.flag & XValue || nxagentUserGeometry.flag & YValue) + sizeHints.flags |= USPosition; + if (nxagentUserGeometry.flag & WidthValue || nxagentUserGeometry.flag & HeightValue) + sizeHints.flags |= USSize; + + XSetStandardProperties(nxagentDisplay, + nxagentDefaultWindows[pScreen->myNum], + nxagentWindowName, + nxagentWindowName, + nxagentIconPixmap, + argv, argc, &sizeHints); + + wmHints.icon_pixmap = nxagentIconPixmap; + + if (useXpmIcon) + { + wmHints.icon_mask = nxagentIconShape; + wmHints.flags = IconPixmapHint | IconMaskHint; + } + else + { + wmHints.flags = IconPixmapHint; + } + + XSetWMHints(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], &wmHints); + + /* + * Clear the window but let it unmapped. We'll map it + * at the time the we'll initialize our screen root + * and only if we are not running in rootless mode. + */ + + XClearWindow(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum]); + + if (nxagentOption(AllScreens)) + { + if (nxagentReconnectTrap) + { + XGrabKeyboard(nxagentDisplay, nxagentFullscreenWindow, True, GrabModeAsync, + GrabModeAsync, CurrentTime); + } + + nxagentIconWindow = nxagentCreateIconWindow(); + } + else + { + nxagentIconWindow = 0; + } + + /* + * When we don't have window manager we grab keyboard + * to let nxagent get keyboard events. + */ + + if (!nxagentWMIsRunning && !nxagentOption(Fullscreen)) + { + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: No window manager, we call XGrabKeyboard.\n"); + #endif + + XGrabKeyboard(nxagentDisplay, RootWindow (nxagentDisplay, 0), True, GrabModeAsync, + GrabModeAsync, CurrentTime); + } + } + + if (!nxagentCreateDefaultColormap(pScreen)) + { + #ifdef PANIC + fprintf(stderr, "nxagentOpenScreen: Failed to create default colormap for screen.\n"); + #endif + + return False; + } + + /* + * The purpose of this check is to verify if there + * is a window manager running. Unfortunately due + * to the way we manage the intern atoms call, the + * atom will always exist. + */ + + if (nxagentWMIsRunning) + { + XlibAtom deleteWMatom = nxagentAtoms[2]; /* WM_DELETE_WINDOW */ + + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: Found WM, delete window atom [%ld].\n", + deleteWMatom); + #endif + + if (nxagentOption(Rootless) == False) + { + /* + * Set the WM_DELETE_WINDOW protocol for the main agent + * window and, if we are in fullscreen mode, include the + * icon window. + */ + + XSetWMProtocols(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], &deleteWMatom, 1); + } + else + { + /* + * We need to register the ICCCM WM_DELETE_WINDOW + * protocol for any top-level window or the agent + * will be killed if any window is closed. + */ + + XSetWMProtocols(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], &deleteWMatom, 1); + + #ifdef TEST + fprintf(stderr, "Warning: Not setting the WM_DELETE_WINDOW protocol.\n"); + #endif + } + } + else + { + /* + * We should always enable the configuration of the + * remote X server's devices if we are running full- + * screen and there is no WM running. + */ + + if (nxagentOption(Fullscreen)) + { + #ifdef TEST + fprintf(stderr, "nxagentOpenScreen: WARNING! Forcing propagation of device control changes.\n"); + #endif + + nxagentChangeOption(DeviceControl, True); + } + } + + /* + * Inform the user whether the agent's clients will + * be able to change the real X server's keyboard + * and pointer settings. + */ + + if (nxagentOption(DeviceControl) == False) + { + fprintf(stderr, "Info: Not using local device configuration changes.\n"); + } + else + { + fprintf(stderr, "Info: Using local device configuration changes.\n"); + } + + #ifdef RENDER + + /* + * if (nxagentRenderEnable && !nxagentReconnectTrap) + * { + * if (!nxagentPictureInit(pScreen, 0, 0)) + * { + * nxagentRenderEnable = False; + * + * return FALSE; + * } + * + * if (nxagentAlphaEnabled) + * { + * fprintf(stderr, "Info: Using alpha channel in render extension.\n"); + * } + * } + */ + + #endif /* RENDER */ + + /* + * Check if the composite extension is + * supported on the remote display and + * prepare the agent for its use. + */ + + nxagentCompositeExtensionInit(); + + /* We use this to get informed about RandR changes on the real display. + FIXME: It would probably be better to use an RRScreenChangeNotifyEvent here. */ + XSelectInput(nxagentDisplay, DefaultRootWindow(nxagentDisplay), StructureNotifyMask); + + #ifdef NXAGENT_TIMESTAMP + + { + extern unsigned long startTime; + + fprintf(stderr, "Screen: open screen finished, time is [%d] milliseconds.\n", + GetTimeInMillis() - startTime); + } + + #endif + + #ifdef WATCH + + fprintf(stderr, "nxagentOpenScreen: Watchpoint 8.\n"); + +/* +Reply Total Cached Bits In Bits Out Bits/Reply Ratio +------- ----- ------ ------- -------- ---------- ----- +#1 U 2 1 5344 bits (1 KB) -> 2344 bits (0 KB) -> 2672/1 -> 1172/1 = 2.280:1 +#16 11 2816 bits (0 KB) -> 197 bits (0 KB) -> 256/1 -> 18/1 = 14.294:1 +#91 1 16640 bits (2 KB) -> 12314 bits (2 KB) -> 16640/1 -> 12314/1 = 1.351:1 +#98 2 512 bits (0 KB) -> 57 bits (0 KB) -> 256/1 -> 28/1 = 8.982:1 +*/ + + sleep(30); + + #endif + + return True; +} + +Bool nxagentCloseScreen(ScreenPtr pScreen) +{ + int i; + + #ifdef DEBUG + fprintf(stderr, "running nxagentCloseScreen()\n"); + #endif + + for (i = 0; i < pScreen->numDepths; i++) + { + free(pScreen->allowedDepths[i].vids); + } + + /* + * Free the frame buffer. + */ + + free(((PixmapPtr)pScreen -> devPrivate) -> devPrivate.ptr); + + free(pScreen->allowedDepths); + free(pScreen->visuals); + free(pScreen->devPrivate); + + /* + * Reset the geometry and alpha information + * used by proxy to unpack the packed images. + */ + + nxagentResetVisualCache(); + nxagentResetAlphaCache(); + nxagentReleaseAllSplits(); + + /* + * The assumption is that all X resources will be + * destroyed upon closing the display connection. + * There is no need to generate extra protocol. + */ + + return True; +} + +/* + * This function comes from the xfree86 Xserver. + */ + +static void nxagentSetRootClip (ScreenPtr pScreen, Bool enable) +{ + WindowPtr pWin = pScreen->root; + WindowPtr pChild; + Bool WasViewable = (Bool)(pWin->viewable); + Bool anyMarked = FALSE; + RegionPtr pOldClip = NULL, bsExposed; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + WindowPtr pLayerWin; + BoxRec box; + + if (WasViewable) + { + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + (void) (*pScreen->MarkOverlappedWindows)(pChild, + pChild, + &pLayerWin); + } + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = RegionCreate(NullBox, 1); + RegionSubtract(borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + pWin->valdata->before.resized = TRUE; + } + } + + /* + * Use REGION_BREAK to avoid optimizations in ValidateTree + * that assume the root borderClip can't change well, normally + * it doesn't...) + */ + if (enable) + { + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + RegionInit(&pWin->winSize, &box, 1); + RegionInit(&pWin->borderSize, &box, 1); + if (WasViewable) + RegionReset(&pWin->borderClip, &box); + pWin->drawable.width = pScreen->width; + pWin->drawable.height = pScreen->height; + RegionBreak(&pWin->clipList); + } + else + { + RegionEmpty(&pWin->borderClip); + RegionBreak(&pWin->clipList); + } + + ResizeChildrenWinSize (pWin, 0, 0, 0, 0); + + if (WasViewable) + { + if (pWin->backStorage) + { + pOldClip = RegionCreate(NullBox, 1); + RegionCopy(pOldClip, &pWin->clipList); + } + + if (pWin->firstChild) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, + pWin->firstChild, + (WindowPtr *)NULL); + } + else + { + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + } + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + { + dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin); + } +#endif /* DO_SAVE_UNDERS */ + + if (anyMarked) + (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); + } + + if (pWin->backStorage && pOldClip && + ((pWin->backingStore == Always) || WasViewable)) + { + if (!WasViewable) + pOldClip = &pWin->clipList; /* a convenient empty region */ + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, 0, 0, pOldClip, + pWin->drawable.x, pWin->drawable.y); + if (WasViewable) + RegionDestroy(pOldClip); + if (bsExposed) + { + RegionPtr valExposed = NullRegion; + + if (pWin->valdata) + valExposed = &pWin->valdata->after.exposed; + (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); + if (valExposed) + RegionEmpty(valExposed); + RegionDestroy(bsExposed); + } + } + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pWin); +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin); +#endif /* DO_SAVE_UNDERS */ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + FlushAllOutput (); +} + +Bool nxagentResizeScreen(ScreenPtr pScreen, int width, int height, + int mmWidth, int mmHeight) +{ + BoxRec box; + XSizeHints sizeHints; + PixmapPtr pPixmap; + char *fbBits; + + int oldWidth; + int oldHeight; + int oldMmWidth; + int oldMmHeight; + + #ifdef TEST + nxagentPrintAgentGeometry("Before Resize Screen", "nxagentResizeScreen:"); + #endif + + /* + * Change screen properties. + */ + + oldWidth = pScreen -> width; + oldHeight = pScreen -> height; + oldMmWidth = pScreen -> mmWidth; + oldMmHeight = pScreen -> mmHeight; + + pScreen -> width = width; + pScreen -> height = height; + + /* + * Compute screen dimensions if they aren't given. + */ + + if (mmWidth == 0) + { + mmWidth = (width * 254 + monitorResolution * 5) / (monitorResolution * 10); + + if (mmWidth < 1) + { + mmWidth = 1; + } + } + + if (mmHeight == 0) + { + mmHeight = (height * 254 + monitorResolution * 5) / (monitorResolution * 10); + + if (mmHeight < 1) + { + mmHeight = 1; + } + } + + pScreen -> mmWidth = mmWidth; + pScreen -> mmHeight = mmHeight; + + pPixmap = fbGetScreenPixmap(pScreen); + + if ((fbBits = realloc(pPixmap -> devPrivate.ptr, PixmapBytePad(width, pScreen->rootDepth) * + height * BitsPerPixel(pScreen->rootDepth) / 8)) == NULL) + { + pScreen -> width = oldWidth; + pScreen -> height = oldHeight; + pScreen -> mmWidth = oldMmWidth; + pScreen -> mmHeight = oldMmHeight; + + goto nxagentResizeScreenError; + } + + if (!miModifyPixmapHeader(pPixmap, width, height, + pScreen->rootDepth, BitsPerPixel(pScreen->rootDepth), + PixmapBytePad(width, + pScreen->rootDepth), fbBits)) + { +/* +FIXME: We should try to restore the previously + reallocated frame buffer pixmap. +*/ + + pScreen -> width = oldWidth; + pScreen -> height = oldHeight; + pScreen -> mmWidth = oldMmWidth; + pScreen -> mmHeight = oldMmHeight; + + goto nxagentResizeScreenError; + } + + nxagentChangeOption(RootWidth, width); + nxagentChangeOption(RootHeight, height); + + if (nxagentOption(Fullscreen)) + { + nxagentChangeOption(RootX, (nxagentOption(Width) - + nxagentOption(RootWidth)) / 2); + nxagentChangeOption(RootY, (nxagentOption(Height) - + nxagentOption(RootHeight)) / 2); + } + else + { + nxagentChangeOption(RootX, 0); + nxagentChangeOption(RootY, 0); + } + + nxagentChangeOption(ViewportXSpan, nxagentOption(Width) - nxagentOption(RootWidth)); + nxagentChangeOption(ViewportYSpan, nxagentOption(Height) - nxagentOption(RootHeight)); + + /* + * Change agent window size and size hints. + */ + + if ((nxagentOption(Fullscreen) == 0 && nxagentOption(AllScreens) == 0)) + { + sizeHints.flags = PPosition | PMinSize | PMaxSize; + sizeHints.x = nxagentOption(X); + sizeHints.y = nxagentOption(Y); + + sizeHints.min_width = MIN_NXAGENT_WIDTH; + sizeHints.min_height = MIN_NXAGENT_HEIGHT; + sizeHints.width = width; + sizeHints.height = height; + + if (nxagentOption(DesktopResize) == 1) + { + sizeHints.max_width = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + sizeHints.max_height = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + } + else + { + sizeHints.max_width = nxagentOption(RootWidth); + sizeHints.max_height = nxagentOption(RootHeight); + } + + if (nxagentUserGeometry.flag & XValue || nxagentUserGeometry.flag & YValue) + { + sizeHints.flags |= USPosition; + } + + if (nxagentUserGeometry.flag & WidthValue || nxagentUserGeometry.flag & HeightValue) + { + sizeHints.flags |= USSize; + } + + XSetWMNormalHints(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], &sizeHints); + + XResizeWindow(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], width, height); + + if (nxagentOption(Rootless) == 0) + { + XResizeWindow(nxagentDisplay, nxagentInputWindows[pScreen -> myNum], width, height); + } + } + + /* + * Set properties for the agent root window. + */ + + box.x1 = 0; + box.y1 = 0; + box.x2 = width; + box.y2 = height; + + pScreen->root -> drawable.width = width; + pScreen->root -> drawable.height = height; + pScreen->root -> drawable.x = 0; + pScreen->root -> drawable.y = 0; + + RegionInit(&pScreen->root -> borderSize, &box, 1); + RegionInit(&pScreen->root -> winSize, &box, 1); + RegionInit(&pScreen->root -> clipList, &box, 1); + RegionInit(&pScreen->root -> borderClip, &box, 1); + + (*pScreen -> PositionWindow)(pScreen->root, 0, 0); + + nxagentSetRootClip(pScreen, 1); + + XMoveWindow(nxagentDisplay, nxagentWindow(screenInfo.screens[0]->root), + nxagentOption(RootX), nxagentOption(RootY)); + + nxagentMoveViewport(pScreen, 0, 0); + + /* + * Update void * bounds. + */ + + ScreenRestructured(pScreen); + + #ifdef TEST + nxagentPrintAgentGeometry("After Resize Screen", "nxagentResizeScreen:"); + #endif + + nxagentSetPrintGeometry(pScreen -> myNum); + + return 1; + +nxagentResizeScreenError: + + return 0; +} + +void nxagentShadowSetRatio(float floatXRatio, float floatYRatio) +{ + int intXRatio; + int intYRatio; + + if (floatXRatio == 0) + { + floatXRatio = 1.0; + } + + if (floatYRatio == 0) + { + floatYRatio = 1.0; + } + + intXRatio = floatXRatio * (1 << PRECISION); + intYRatio = floatYRatio * (1 << PRECISION); + + nxagentChangeOption(FloatXRatio, floatXRatio); + nxagentChangeOption(FloatYRatio, floatYRatio); + + nxagentChangeOption(XRatio, intXRatio); + nxagentChangeOption(YRatio, intYRatio); + + #ifdef TEST + fprintf(stderr, "Info: Using X ratio [%f] Y ratio [%f].\n", + nxagentOption(FloatXRatio), nxagentOption(FloatYRatio)); + #endif +} + +void nxagentShadowSetWindowsSize(void) +{ + XResizeWindow(nxagentDisplay, nxagentDefaultWindows[0], + nxagentOption(Width), nxagentOption(Height)); + + XMoveResizeWindow(nxagentDisplay, nxagentInputWindows[0], 0, 0, + nxagentOption(Width), nxagentOption(Height)); +} + +void nxagentShadowSetWindowOptions(void) +{ + nxagentChangeOption(RootWidth, nxagentScale(nxagentShadowWidth, nxagentOption(XRatio))); + nxagentChangeOption(RootHeight, nxagentScale(nxagentShadowHeight, nxagentOption(YRatio))); + + nxagentChangeOption(SavedRootWidth, nxagentOption(RootWidth)); + nxagentChangeOption(SavedRootHeight, nxagentOption(RootHeight)); + + nxagentChangeOption(RootX, (nxagentOption(Width) - nxagentOption(RootWidth)) >> 1); + nxagentChangeOption(RootY, (nxagentOption(Height) - nxagentOption(RootHeight)) >> 1); +} + +int nxagentShadowInit(ScreenPtr pScreen, WindowPtr pWin) +{ + int i; + char *layout = NULL; + extern char *nxagentKeyboard; + XlibGC gc; + XGCValues value; + + #ifndef __CYGWIN32__ + + Atom nxagentShadowAtom; + + int fd; + + #endif + + #ifdef TEST + fprintf(stderr, "Info: Init shadow session. nxagentDisplayName [%s] " + "nxagentDisplay [%p] nxagentShadowDisplayName [%s].\n", + nxagentDisplayName, (void *) nxagentDisplay, + nxagentShadowDisplayName); + #endif + + if (nxagentKeyboard != NULL) + { + for (i = 0; nxagentKeyboard[i] != '/' && nxagentKeyboard[i] != 0; i++); + + if(nxagentKeyboard[i] == 0 || nxagentKeyboard[i + 1] == 0 || i == 0) + { + #ifdef WARNING + fprintf(stderr,"WARNING! Wrong keyboard type: %s.\n", nxagentKeyboard); + #endif + } + else + { + layout = malloc(strlen(&nxagentKeyboard[i + 1]) + 1); + + strcpy(layout, &nxagentKeyboard[i + 1]); + } + } + + #ifdef DEBUG + fprintf(stderr, "nxagentShadowInit: Setting the master uid [%d].\n", + nxagentShadowUid); + #endif + +#if !defined (__CYGWIN32__) && !defined (WIN32) + + if (nxagentShadowUid != -1) + { + NXShadowSetDisplayUid(nxagentShadowUid); + } + + if (nxagentOption(UseDamage) == 0) + { + NXShadowDisableDamage(); + } + +#endif + + if (NXShadowCreate(nxagentDisplay, layout, nxagentShadowDisplayName, + (void *) &nxagentShadowDisplay) != 1) + { + #ifdef PANIIC + fprintf(stderr, "nxagentShadowInit: PANIC! Failed to initialize shadow " + "display [%s].\n", nxagentShadowDisplayName); + #endif + + return -1; + } + + /* + * The shadow nxagent sets the _NX_SHADOW + * property on the master X server root + * window in order to notify its presence. + */ + + #ifndef __CYGWIN__ + + nxagentShadowAtom = XInternAtom(nxagentShadowDisplay, "_NX_SHADOW", False); + + XChangeProperty(nxagentShadowDisplay, DefaultRootWindow(nxagentShadowDisplay), + nxagentShadowAtom, XA_STRING, 8, PropModeReplace, NULL, 0); + #endif + + if (NXShadowAddUpdaterDisplay(nxagentDisplay, &nxagentShadowWidth, + &nxagentShadowHeight, &nxagentMasterDepth) == 0) + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowInit: PANIC! Failed to add display [%s].\n", + nxagentDisplayName); + #endif + + return -1; + } + + #ifndef __CYGWIN32__ + + if (nxagentOption(Fullscreen) == 1) + { + nxagentShadowSetRatio(WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) * 1.0 / nxagentShadowWidth, + HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) * 1.0 / nxagentShadowHeight); + } + else if (nxagentUserGeometry.flag != 0) + { + nxagentShadowSetRatio(nxagentOption(RootWidth) * 1.0 / nxagentShadowWidth, + nxagentOption(RootHeight) * 1.0 / nxagentShadowHeight); + } + + if (DefaultVisualOfScreen(DefaultScreenOfDisplay(nxagentDisplay)) -> + class != TrueColor) + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowInit: PANIC! The visual class of the remote " + "X server is not TrueColor.\n"); + #endif + + return -1; + } + + if (DefaultVisualOfScreen(DefaultScreenOfDisplay(nxagentShadowDisplay)) -> + class != TrueColor) + { + #ifdef PANIC + + const char *className; + + switch (DefaultVisualOfScreen(DefaultScreenOfDisplay(nxagentShadowDisplay)) -> class) + { + case StaticGray: + { + className = "StaticGray"; + + break; + } + case StaticColor: + { + className = "StaticColor"; + + break; + } + case PseudoColor: + { + className = "PseudoColor"; + + break; + } + case DirectColor: + { + className = "DirectColor"; + + break; + } + case GrayScale: + { + className = "GrayScale"; + + break; + } + default: + { + className = ""; + + break; + } + } + + fprintf(stderr, "nxagentShadowInit: PANIC! Cannot shadow the display. " + "%s visual class is not supported. Only TrueColor visuals " + "are supported.\n", className); + + #endif /* #endif PANIC */ + + return -1; + } + + #endif + + nxagentShadowDepth = pScreen -> rootDepth; + + switch (nxagentMasterDepth) + { + case 32: + case 24: + { + if (nxagentShadowDepth == 16) + { + nxagentCheckDepth = 1; + } + else if (nxagentShadowDepth == 8) + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowInit: PANIC! Unable to shadow a %d bit " + "display with a 8 bit screen depth.\n", nxagentMasterDepth); + #endif + + return -1; + } + + nxagentBppMaster = 4; + + break; + } + case 16: + { + if (nxagentShadowDepth > 16) + { + nxagentCheckDepth = 1; + } + else if (nxagentShadowDepth == 8) + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowInit: PANIC! Unable to shadow a 16 bit " + "display with a 8 bit screen depth.\n"); + #endif + + return -1; + } + + nxagentBppMaster = 2; + + break; + } + case 8: + { + if (nxagentShadowDepth != 8) + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowInit: PANIC! Unable to shadow a 8 bit " + "display with a %d bit screen depth.\n", nxagentShadowDepth); + #endif + + return -1; + } + + nxagentBppMaster = 1; + + break; + } + default: + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowInit: PANIC! The depth is not 32, 24, 16 or 8 bit.\n"); + #endif + + return -1; + } + } + + if (nxagentShadowDepth >= 24) + { + nxagentBppShadow = 4; + } + else if (nxagentShadowDepth == 16) + { + nxagentBppShadow = 2; + } + else if (nxagentShadowDepth == 8) + { + nxagentBppShadow = 1; + } + +#if !defined(__CYGWIN__) + + imageByteOrder = nxagentShadowDisplay -> byte_order; + + fd = XConnectionNumber(nxagentShadowDisplay); + + nxagentShadowXConnectionNumber = fd; + +#endif + + #ifdef TEST + fprintf(stderr, "nxagentAddXConnection: Adding the X connection [%d] " + "to the device set.\n", fd); + #endif + + SetNotifyFd(nxagentShadowXConnectionNumber, nxagentNotifyConnection, X_NOTIFY_READ, NULL); + + accessPixmapID = FakeClientID(serverClient -> index); + + AddResource(accessPixmapID, RT_PIXMAP, (void *)nxagentShadowPixmapPtr); + + accessWindowID = FakeClientID(serverClient -> index); + + AddResource(accessWindowID, RT_WINDOW, (void *)nxagentShadowWindowPtr); + + nxagentResizeScreen(pScreen, nxagentShadowWidth, nxagentShadowHeight, pScreen -> mmWidth, pScreen -> mmHeight); + + nxagentShadowCreateMainWindow(pScreen, pWin, nxagentShadowWidth, nxagentShadowHeight); + + if (nxagentRemoteMajor <= 3) + { + nxagentShadowSetWindowsSize(); + + nxagentSetWMNormalHints(0); + } + + XMapWindow(nxagentDisplay, nxagentDefaultWindows[0]); + + /* + * Clean up the main window. + */ + + value.foreground = 0x00000000; + value.background = 0x00000000; + value.plane_mask = 0xffffffff; + value.fill_style = FillSolid; + + gc = XCreateGC(nxagentDisplay, nxagentPixmap(nxagentShadowPixmapPtr), GCBackground | + GCForeground | GCFillStyle | GCPlaneMask, &value); + + XFillRectangle(nxagentDisplay, nxagentPixmap(nxagentShadowPixmapPtr), gc, 0, 0, + nxagentShadowWidth, nxagentShadowHeight); + + XFreeGC(nxagentDisplay, gc); + + RegionInit(&nxagentShadowUpdateRegion, (BoxRec*)NULL, 1); + + return 0; +} + +int nxagentShadowCreateMainWindow(ScreenPtr pScreen, WindowPtr pWin, int width, int height) +{ + XWindowChanges changes; + Mask mask,maskb; + XID values[4], *vlist; + int error; + XID xid; + + nxagentShadowWidth = width; + nxagentShadowHeight = height; + + NXShadowUpdateBuffer((void *)&nxagentShadowBuffer); + + #ifdef TEST + fprintf(stderr, "nxagentShadowCreateMainWindow: Update frame buffer [%p].\n", nxagentShadowBuffer); + #endif + + nxagentShadowSetWindowOptions(); + + if (nxagentShadowPixmapPtr != NULL) + { + nxagentDestroyPixmap(nxagentShadowPixmapPtr); + } + + if (nxagentShadowWindowPtr != NULL) + { + DeleteWindow(nxagentShadowWindowPtr, accessWindowID); + } + + nxagentShadowPixmapPtr = nxagentCreatePixmap(pScreen, nxagentShadowWidth, nxagentShadowHeight, nxagentShadowDepth, 0); + + if (nxagentShadowPixmapPtr) + { + ChangeResourceValue(accessPixmapID, RT_PIXMAP, (void *) nxagentShadowPixmapPtr); + nxagentShadowPixmapPtr -> drawable.id = accessPixmapID; + + #ifdef TEST + fprintf(stderr, "nxagentShadowCreateMainWindow: nxagentShadowPixmapPtr [%p] PixmapM -> drawable.id [%lu].\n", + (void *)nxagentShadowPixmapPtr, nxagentShadowPixmapPtr -> drawable.id); + fprintf(stderr, "nxagentShadowCreateMainWindow: Create pixmap with width [%d] height [%d] depth [%d].\n", + nxagentShadowWidth, nxagentShadowHeight, (int)nxagentShadowDepth); + #endif + } + else + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowCreateMainWindow: PANIC! Failed to create pixmap with width [%d] height [%d] depth [%d].\n", + nxagentShadowWidth, nxagentShadowHeight, (int)nxagentShadowDepth); + #endif + } + + XFreePixmap(nxagentDisplay, nxagentPixmap(nxagentVirtualPixmap(nxagentShadowPixmapPtr))); + + xid = XCreatePixmap(nxagentDisplay, nxagentDefaultWindows[0], + nxagentScale(nxagentShadowWidth, nxagentOption(XRatio)), + nxagentScale(nxagentShadowHeight, nxagentOption(YRatio)), nxagentShadowDepth); + + nxagentPixmap(nxagentVirtualPixmap(nxagentShadowPixmapPtr)) = xid; + + nxagentPixmap(nxagentRealPixmap(nxagentShadowPixmapPtr)) = xid; + + if (nxagentShadowGCPtr != NULL) + { + FreeScratchGC(nxagentShadowGCPtr); + } +/* + * FIXME: Should use CreateGC. + */ + nxagentShadowGCPtr = GetScratchGC(nxagentShadowPixmapPtr -> drawable.depth, nxagentShadowPixmapPtr -> drawable.pScreen); + + if (nxagentShadowGCPtr) + { + #ifdef TEST + fprintf(stderr, "nxagentShadowCreateMainWindow: Created GC with pGC[%p]\n", (void *) nxagentShadowGCPtr); + #endif + ValidateGC((DrawablePtr)nxagentShadowPixmapPtr, nxagentShadowGCPtr); + } + else + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowCreateMainWindow: PANIC! Failed to create GC."); + #endif + } + + mask = CWBackPixmap | CWEventMask | CWCursor; + + nxagentGetDefaultEventMask(&maskb); + maskb |= ResizeRedirectMask | ExposureMask; + + vlist = values; + *vlist++ = (XID)nxagentShadowPixmapPtr -> drawable.id; + *vlist++ = (XID)maskb; + + *vlist = (XID)None; + + nxagentShadowWindowPtr = CreateWindow(accessWindowID, pWin, 0, 0, nxagentShadowWidth, + nxagentShadowHeight, 0, InputOutput, mask, (XID *)values, + nxagentShadowDepth, serverClient, CopyFromParent, &error); + + mask = CWWidth | CWHeight; + changes.width = nxagentScale(nxagentShadowWidth, nxagentOption(XRatio)); + changes.height = nxagentScale(nxagentShadowHeight, nxagentOption(YRatio)); + + XConfigureWindow(nxagentDisplay, nxagentWindow(nxagentShadowWindowPtr), mask, &changes); + + nxagentMoveViewport(pScreen, 0, 0); + + if (nxagentShadowWindowPtr && !error) + { + #ifdef TEST + fprintf(stderr, "nxagentShadowCreateMainWindow: Create window with nxagentShadowWindowPtr [%p]" + "nxagentShadowWindowPtr -> drawable.id [%lu].\n", (void *) nxagentShadowWindowPtr, + nxagentShadowWindowPtr -> drawable.id); + + fprintf(stderr, "nxagentShadowCreateMainWindow: parent nxagentShadowWindowPtr [%p] parent -> drawable.id [%lu].\n", + (void *)nxagentShadowWindowPtr->parent, nxagentShadowWindowPtr -> parent -> drawable.id); + + #endif + + ChangeResourceValue(accessWindowID, RT_WINDOW, (void *) nxagentShadowWindowPtr); + } + else + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowCreateMainWindow: PANIC! Failed to create window.\n"); + #endif + } + + XMapWindow(nxagentDisplay, nxagentWindow(nxagentShadowWindowPtr)); + MapWindow(nxagentShadowWindowPtr, serverClient); + + mask = CWX | CWY | CWWidth | CWHeight; + changes.x = nxagentOption(RootX); + changes.y = nxagentOption(RootY); + changes.width = nxagentScale(nxagentShadowWidth, nxagentOption(XRatio)); + changes.height = nxagentScale(nxagentShadowHeight, nxagentOption(YRatio)); + XConfigureWindow(nxagentDisplay, nxagentWindow(pWin), mask, &changes); + + #ifdef TEST + fprintf(stderr, "nxagentShadowCreateMainWindow: Completed mapping of Access window.\n"); + #endif + + return 0; +} + +int nxagentShadowSendUpdates(int *suspended) +{ + *suspended = 0; + + if (RegionNil(&nxagentShadowUpdateRegion) == 1) + { + return 0; + } + + nxagentMarkCorruptedRegion((DrawablePtr)nxagentShadowPixmapPtr, &nxagentShadowUpdateRegion); + + RegionEmpty(&nxagentShadowUpdateRegion); + + return 1; +} + +int nxagentShadowPoll(PixmapPtr nxagentShadowPixmapPtr, GCPtr nxagentShadowGCPtr, + unsigned char nxagentShadowDepth, int nxagentShadowWidth, + int nxagentShadowHeight, char *nxagentShadowBuffer, int *changed, int *suspended) +{ + int x, y, y2, n, c, line; + int result; + long numRects; + unsigned int width, height, length; + char *tBuffer = NULL; + char *iBuffer, *ptBox; + BoxRec *pBox; + RegionRec updateRegion; + RegionRec tempRegion; + BoxRec box; + int overlap; + + + RegionNull(&updateRegion); + + RegionNull(&tempRegion); + +#ifdef __CYGWIN32__ + + if (NXShadowCaptureCursor(nxagentWindow(nxagentShadowWindowPtr), + nxagentShadowWindowPtr -> drawable.pScreen -> visuals) == -1) + { + #ifdef WARNING + fprintf(stderr, "nxagentShadowPoll: Failed to capture cursor.\n"); + #endif + } + +#endif + + result = NXShadowHasChanged(nxagentUserInput, NULL, suspended); + + *changed = result; + + if (result == 1) + { + if (nxagentWMPassed == 0) + { + nxagentRemoveSplashWindow(NULL); + } + + NXShadowExportChanges(&numRects, &ptBox); + pBox = (BoxRec *)ptBox; + + #ifdef TEST + fprintf(stderr, "nxagentShadowPoll: nRects[%ld], pBox[%p] depth[%d].\n", numRects, (void *) pBox, nxagentShadowDepth); + #endif + + for (n = 0; n < numRects; n++) + { + /* + * The BoxRec struct defined in the Xserver has a different + * variable order in comparison with the BoxRec struct in the Xlib. + * the second and third field are inverted. + */ + + x = pBox[n].x1; + y = pBox[n].x2; + y2 = pBox[n].y2; + width = pBox[n].y1 - pBox[n].x1;/* y1 = x2 */ + height = y2 - pBox[n].x2; /* x2 = y1 */ + + if((x + width) > nxagentShadowWidth || (y + height) > nxagentShadowHeight) + { + /* + * Out of bounds. Maybe a resize of the master session is going on. + */ + + continue; + } + + line = PixmapBytePad(width, nxagentMasterDepth); + + #ifdef DEBUG + fprintf(stderr, "nxagentShadowPoll: Rectangle Number[%d] - x[%d]y[%d]W[%u]H[%u].\n", n+1, x, y, width, height); + #endif + + length = nxagentImageLength(width, height, ZPixmap, 0, nxagentMasterDepth); + + if (tBuffer) + { + free(tBuffer); + } + + tBuffer = malloc(length); + + if (tBuffer == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentShadowPoll: malloc failed.\n"); + #endif + + return -1; + } + + iBuffer = tBuffer; + + for (c = 0; c + y < y2; c++) + { + memcpy(tBuffer, nxagentShadowBuffer + x * nxagentBppMaster + + (y + c) * nxagentShadowWidth * nxagentBppMaster, line); + + tBuffer += line; + + } + + tBuffer = iBuffer; + +#ifdef __CYGWIN32__ + if (nxagentBppMaster == 2) + { + NXShadowCorrectColor(length, tBuffer); + } +#else + if (nxagentCheckDepth == 1) + { + nxagentShadowAdaptDepth(width, height, line, &tBuffer); + } +#endif + + fbPutImage(nxagentVirtualDrawable((DrawablePtr)nxagentShadowPixmapPtr), nxagentShadowGCPtr, + nxagentShadowDepth, x, y, width, height, 0, ZPixmap, tBuffer); + + box.x1 = x; + box.x2 = x + width; + box.y1 = y; + box.y2 = y + height; + + RegionInit(&tempRegion, &box, 1); + + RegionAppend(&updateRegion, &tempRegion); + + RegionUninit(&tempRegion); + + RegionValidate(&updateRegion, &overlap); + + RegionUnion(&nxagentShadowUpdateRegion, &nxagentShadowUpdateRegion, &updateRegion); + } + + if (tBuffer) + { + free(tBuffer); + } + + RegionUninit(&updateRegion); + } + else if (result == -1) + { + #ifdef TEST + fprintf(stderr, "nxagentShadowPoll: polling failed!\n"); + #endif + + usleep(50 * 1000); + + return -1; + } + + return 0; +} + +void nxagentShadowAdaptDepth(unsigned int width, unsigned int height, + unsigned int lineMaster, char **buffer) +{ + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned short color16 = 0; + unsigned char * icBuffer; + unsigned char * cBuffer = NULL; + unsigned char * tBuffer = (unsigned char *) *buffer; + unsigned int lineShadow; + unsigned int length; + unsigned int c; + unsigned int pad; + unsigned int color32 = 0; + unsigned long redMask; + unsigned long greenMask; + unsigned long blueMask; + Visual *pVisual; + + length = nxagentImageLength(width, height, ZPixmap, 0, nxagentShadowDepth); + + cBuffer = malloc(length); + icBuffer = cBuffer; + + pVisual = nxagentImageVisual((DrawablePtr) nxagentShadowPixmapPtr, nxagentShadowDepth); + + if (pVisual == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentCorrectDepthShadow: WARNING! Visual not found. Using default visual.\n"); + #endif + + pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual; + } + + #ifdef TEST + fprintf(stderr, "nxagentCorrectDepthShadow: Shadow redMask [%lu] greenMask[%lu] blueMask[%lu].\n", + pVisual -> red_mask, pVisual -> green_mask, pVisual -> blue_mask); + #endif + + redMask = nxagentShadowDisplay -> screens[0].root_visual[0].red_mask; + greenMask = nxagentShadowDisplay -> screens[0].root_visual[0].green_mask; + blueMask = nxagentShadowDisplay -> screens[0].root_visual[0].blue_mask; + + #ifdef TEST + fprintf(stderr, "nxagentCorrectDepthShadow: Master redMask [%lu] greenMask[%lu] blueMask[%lu].\n", + redMask, greenMask, blueMask); + #endif + + switch(nxagentMasterDepth) + { + /* + * The Shadow agent has 24 bit depth. + */ + case 16: + { + pad = lineMaster - nxagentBppMaster * width; + + #ifdef TEST + fprintf(stderr, "nxagentCorrectDepthShadow: line [%d] width[%d] pad[%d].\n", lineMaster, width, pad); + #endif + + while (height > 0) + { + for (c = 0; c < width ; c++) + { + if (imageByteOrder == LSBFirst) + { + color16 = *tBuffer++; + color16 |= (*tBuffer << 8); + } + else + { + color16 = (*tBuffer++) << 8; + color16 |= *tBuffer; + } + + blue = ((short) blueMask & color16) << 3; + blue |= 0x3; + + if (greenMask == 0x7e0) + { + /* + * bit mask 5-6-5 + */ + + green = ((short) greenMask & color16) >> 3; + green |= 0x2; + + red = ((short) redMask & color16) >> 8; + red |= 0x3; + } + else + { + /* + * bit mask 5-5-5 + */ + + green = ((short) greenMask & color16) >> 2; + green |= 0x3; + + red = ((short) redMask & color16) >> 7; + red |= 0x3; + } + + tBuffer++; + + if (nxagentDisplay -> byte_order == LSBFirst) + { + *cBuffer++ = blue; + *cBuffer++ = green; + *cBuffer++ = red; + cBuffer++; + } + else + { + cBuffer++; + *cBuffer++ = red; + *cBuffer++ = green; + *cBuffer++ = blue; + } + } + tBuffer += pad; + height--; + } + break; + } + + /* + * The Shadow agent has 16 bit depth. + */ + case 24: + { + lineShadow = PixmapBytePad(width, nxagentShadowDepth); + + pad = lineShadow - nxagentBppShadow * width; + + #ifdef TEST + fprintf(stderr, "nxagentCorrectDepthShadow: line [%d] width[%d] pad[%d].\n", lineShadow, width, pad); + #endif + + while (height > 0) + { + for (c = 0; c < width; c++) + { + if (imageByteOrder == LSBFirst) + { + color32 = *tBuffer++; + color32 |= (*tBuffer++ << 8); + color32 |= (*tBuffer++ << 16); + tBuffer++; + } + else + { + tBuffer++; + color32 = (*tBuffer++ << 16); + color32 |= (*tBuffer++ << 8); + color32 |= *tBuffer++; + } + + color16 = (color32 & (pVisual -> blue_mask << 3)) >> 3; + + if (pVisual -> green_mask == 0x7e0) + { + /* + * bit mask 5-6-5 + */ + color16 |= (color32 & (pVisual -> green_mask << 5)) >> 5; + color16 |= (color32 & (pVisual -> red_mask << 8)) >> 8; + } + else + { + /* + * bit mask 5-5-5 + */ + color16 |= (color32 & (pVisual -> green_mask << 6)) >> 6; + color16 |= (color32 & (pVisual -> red_mask << 9)) >> 9; + } + + if (nxagentDisplay -> byte_order == LSBFirst) + { + *cBuffer++ = color16 & 0xff; + *cBuffer++ = (color16 & 0xff00) >> 8; + } + else + { + *cBuffer++ = (color16 & 0xff00) >> 8; + *cBuffer++ = color16 & 0xff; + } + } + cBuffer += pad; + height--; + } + break; + } + } + cBuffer = (unsigned char *) *buffer; + *buffer = (char *) icBuffer; + + if (cBuffer != NULL) + { + free(cBuffer); + } +} + +#ifdef NXAGENT_ARTSD + +unsigned char fromHexNibble(char c) +{ + int uc = (unsigned char)c; + + if(uc >= '0' && uc <= '9') return uc - (unsigned char)'0'; + if(uc >= 'a' && uc <= 'f') return uc + 10 - (unsigned char)'a'; + if(uc >= 'A' && uc <= 'F') return uc + 10 - (unsigned char)'A'; + + return 16; /*error*/ +} + +void nxagentPropagateArtsdProperties(ScreenPtr pScreen, char *port) +{ + Window rootWin; + XlibAtom atomReturnType; + XlibAtom propAtom; + int iReturnFormat; + unsigned long ulReturnItems; + unsigned long ulReturnBytesLeft; + unsigned char *pszReturnData = NULL; + int iReturn; + + int i,in; + char tchar[] = " "; +/* +FIXME: The port information is not used at the moment and produces a + warning on recent gcc versions. Do we need such information + to run the audio forawrding? + + char *chport; + char hex[] = "0123456789abcdef"; +*/ + rootWin = DefaultRootWindow(nxagentDisplay); + propAtom = nxagentAtoms[4]; /* MCOPGLOBALS */ + + /* + * Get at most 64KB of data. + */ + + iReturn = XGetWindowProperty(nxagentDisplay, + rootWin, + propAtom, + 0, + 65536 / 4, + False, + XA_STRING, + &atomReturnType, + &iReturnFormat, + &ulReturnItems, + &ulReturnBytesLeft, + &pszReturnData); + + if (iReturn == Success && atomReturnType != None && + ulReturnItems > 0 && pszReturnData != NULL) + { + char *local_buf; + + #ifdef TEST + fprintf(stderr, "nxagentPropagateArtsdProperties: Got [%ld] elements of format [%d] with [%ld] bytes left.\n", + ulReturnItems, iReturnFormat, ulReturnBytesLeft); + #endif + + #ifdef WARNING + + if (ulReturnBytesLeft > 0) + { + fprintf(stderr, "nxagentPropagateArtsdProperties: WARNING! Could not get the whole ARTSD property data.\n"); + } + + #endif + + local_buf = (char *) malloc(strlen((char*)pszReturnData) + 100); + + if (local_buf) + { + memset(local_buf, 0, strlen((char *) pszReturnData)); + + for (i = 0, in = 0; pszReturnData[i] != '\0'; i++) + { + local_buf[in]=pszReturnData[i]; + + if(pszReturnData[i]==':') + { + i++; + + while(pszReturnData[i]!='\n') + { + unsigned char h; + unsigned char l; + + h = fromHexNibble(pszReturnData[i]); + i++; + if(pszReturnData[i]=='\0') continue; + l = fromHexNibble(pszReturnData[i]); + i++; + + if(h >= 16 || l >= 16) continue; + + /* + * FIXME: The array tchar[] was used uninitialized. + * It's not clear to me the original purpose of the + * piece of code using it. To be removed in future + * versions. + */ + + tchar[0]=tchar[1]; + tchar[1]=tchar[2]; + tchar[2]=tchar[3]; + tchar[3] = (h << 4) + l; + tchar[4]='\0'; + + if (strncmp(tchar, "tcp:", 4) == 0) + { + local_buf[in-7]='1'; + local_buf[in-6]=strlen(port)+47; + + in++; + local_buf[in]=pszReturnData[i-2]; + in++; + local_buf[in]=pszReturnData[i-1]; + + strcat(local_buf,"6c6f63616c686f73743a"); + in+=20; + +/* +FIXME: The port information is not used at the moment and produces a + warning on recent gcc versions. Do we need such information + to run the audio forawrding? + + chport=&port[0]; + + while(*chport!='\0') + { + in++; + local_buf[in]=hex[(*chport >> 4) & 0xf]; + in++; + local_buf[in]=hex[*chport & 0xf]; + *chport++; + } +*/ + strcat(local_buf,"00"); + in+=2; + + while(pszReturnData[i]!='\n') + { + i++; + } + } + else + { + in++; + local_buf[in]=pszReturnData[i-2]; + in++; + local_buf[in]=pszReturnData[i-1]; + } + } + + in++; + local_buf[in]=pszReturnData[i]; + } + + in++; + } + + local_buf[in]=0; + + if (strlen(local_buf)) + { + mcop_local_atom = MakeAtom(mcop_atom, strlen(mcop_atom), 1); + + ChangeWindowProperty(pScreen->root, + mcop_local_atom, + XA_STRING, + iReturnFormat, PropModeReplace, + strlen(local_buf), local_buf, 1); + } + + free(local_buf); + } + } +} + +#endif + +Bool nxagentReconnectScreen(void *p0) +{ + CARD16 w, h; + PixmapPtr pPixmap = (PixmapPtr)nxagentDefaultScreen->devPrivate; + Mask mask; + +#if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_SCREEN_DEBUG) + fprintf(stderr, "nxagentReconnectScreen\n"); +#endif + + if (!nxagentOpenScreen(nxagentDefaultScreen, nxagentArgc, nxagentArgv)) + { + return False; + } + + nxagentPixmap(pPixmap) = XCreatePixmap(nxagentDisplay, + nxagentDefaultWindows[nxagentDefaultScreen->myNum], + pPixmap -> drawable.width, + pPixmap -> drawable.height, + pPixmap -> drawable.depth); +#ifdef NXAGENT_RECONNECT_SCREEN_DEBUG + fprintf(stderr, "nxagentReconnectScreen: recreated %p - ID %lx\n", + pPixmap, + nxagentPixmap( pPixmap )); +#endif + w = 16; + h = 16; + (*nxagentDefaultScreen->QueryBestSize)(StippleShape, &w, &h, nxagentDefaultScreen); + if (!(nxagentPixmap(nxagentDefaultScreen->PixmapPerDepth[0]) = + XCreatePixmap(nxagentDisplay, + nxagentDefaultDrawables[1], + w, + h, + 1))); + + nxagentGetDefaultEventMask(&mask); + mask |= NXAGENT_KEYBOARD_EVENT_MASK | NXAGENT_POINTER_EVENT_MASK; + nxagentSetDefaultEventMask(mask); + XSelectInput(nxagentDisplay, nxagentDefaultWindows[0], mask); + + /* + * Turn off the screen-saver and reset the + * time to the next auto-disconnection. + */ + + SaveScreens(SCREEN_SAVER_OFF, ScreenSaverActive); + + lastDeviceEventTime.milliseconds = GetTimeInMillis(); + + return True; +} + +/* intersect two rectangles */ +Bool intersect(int ax1, int ay1, unsigned int aw, unsigned int ah, + int bx1, int by1, unsigned int bw, unsigned int bh, + int *x, int *y, unsigned int *w, unsigned int *h) +{ + int tx1, ty1, tx2, ty2, ix, iy; + unsigned int iw, ih; + + int ax2 = ax1 + aw; + int ay2 = ay1 + ah; + int bx2 = bx1 + bw; + int by2 = by1 + bh; + + /* thanks to http://silentmatt.com/rectangle-intersection */ + + /* check if there's any intersection at all */ + if (ax2 < bx1 || bx2 < ax1 || ay2 < by1 || by2 < ay1) { + return FALSE; + } + + tx1 = MAX(ax1, bx1); + ty1 = MAX(ay1, by1); + tx2 = MIN(ax2, bx2); + ty2 = MIN(ay2, by2); + + ix = tx1 - ax1; + iy = ty1 - ay1; + iw = tx2 - tx1; + ih = ty2 - ty1; + + /* check if the resulting rectangle is feasible */ + if (iw <= 0 || ih <= 0) { + return FALSE; + } + *x = ix; + *y = iy; + *w = iw; + *h = ih; + return TRUE; +} + +#ifndef NXAGENT_RANDR_XINERAMA_CLIPPING +/* intersect two rectangles, return aw/ah for w/h if resulting + rectangle is (partly) outside of bounding box */ +Bool intersect_bb(int ax1, int ay1, unsigned int aw, unsigned int ah, + int bx1, int by1, unsigned int bw, unsigned int bh, + int bbx1, int bby1, int bbx2, int bby2, + int *x, int *y, unsigned int *w, unsigned int *h) +{ + Bool result = intersect(ax1, ay1, aw, ah, bx1, by1, bw, bh, x, y, w, h); + if (result == TRUE) { + /* check if outside of bounding box */ + if (ax1 < bbx1 || ax1 + aw > bbx2) { + #ifdef DEBUG + fprintf(stderr, "intersect: box has parts outside bounding box - width stays unchanged [%d]\n", aw); + #endif + *w = aw; + } + + if (ay1 < bby1 || ay1 + ah > bby2) { + #ifdef DEBUG + fprintf(stderr, "intersect: box has parts outside bounding box - height stays unchanged [%d]\n", ah); + #endif + *h = ah; + } + } + + return result; +} +#endif + +int nxagentChangeScreenConfig(int screen, int width, int height, int mmWidth, int mmHeight) +{ + ScreenPtr pScreen; + /* FIXME: when is this needed? */ + int doNotify = TRUE; + int r; + + #ifdef DEBUG + fprintf(stderr, "nxagentChangeScreenConfig: called for screen [%d], width [%d] height [%d] mmWidth [%d] mmHeight [%d]\n", screen, width, height, mmWidth, mmHeight); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentChangeScreenConfig: screenInfo.screens[%d]->root [%p]\n", screen, (void *) screenInfo.screens[screen]); + #endif + if (screenInfo.screens[screen]->root == NULL) + { + return 0; + } + + UpdateCurrentTime(); + + #ifdef DEBUG + if (nxagentGrabServerInfo.grabstate == SERVER_GRABBED) + fprintf(stderr, "nxagentChangeScreenConfig: grabstate [SERVER_GRABBED], client [%p]\n", (void *) nxagentGrabServerInfo.client); + else if (nxagentGrabServerInfo.grabstate == SERVER_UNGRABBED) + fprintf(stderr, "nxagentChangeScreenConfig: grabstate [SERVER_UNGRABBED], client [%p]\n", (void *) nxagentGrabServerInfo.client); + else if (nxagentGrabServerInfo.grabstate == CLIENT_PERVIOUS) + fprintf(stderr, "nxagentChangeScreenConfig: grabstate [CLIENT_PERVIOUS], client [%p]\n", (void *) nxagentGrabServerInfo.client); + else if (nxagentGrabServerInfo.grabstate == CLIENT_IMPERVIOUS) + fprintf(stderr, "nxagentChangeScreenConfig: grabstate [CLIENT_IMPERVIOUS], client [%p]\n", (void *) nxagentGrabServerInfo.client); + else + fprintf(stderr, "nxagentChangeScreenConfig: grabstate [UNKNOWN], client [%p]\n", (void *) nxagentGrabServerInfo.client); + #endif + + if (nxagentGrabServerInfo.grabstate == SERVER_GRABBED && nxagentGrabServerInfo.client != NULL) + { + /* + * If any client grabbed the server it won't expect screen + * configuration changes until it releases the grab. That could + * lead to an X error because available modes are changed + * in the meantime. + */ + + #ifdef TEST + fprintf(stderr, "nxagentChangeScreenConfig: Cancel with grabbed server (grab held by [%p]).\n", (void *) nxagentGrabServerInfo.client); + #endif + + return 0; + } + + pScreen = screenInfo.screens[screen] -> root -> drawable.pScreen; + + #ifdef TEST + fprintf(stderr, "nxagentChangeScreenConfig: Changing config to %d x %d (%dmm x %dmm).\n", width, height, mmWidth, mmHeight); + #endif + + r = nxagentResizeScreen(pScreen, width, height, mmWidth, mmHeight); + + if (r != 0) + { + nxagentAdjustRandRXinerama(pScreen); + } + + if (doNotify) + { + RRScreenSizeNotify(pScreen); + } + + #ifdef DEBUG + fprintf(stderr, "nxagentChangeScreenConfig: current geometry: %d,%d %dx%d\n", nxagentOption(X), nxagentOption(Y), nxagentOption(Width), nxagentOption(Height)); + fprintf(stderr, "nxagentChangeScreenConfig: returning [%d]\n", r); + #endif + + return r; +} + +/* + Destroy an output after removing it from any crtc that might reference it + */ +void nxagentDropOutput(RROutputPtr o) { + RRCrtcPtr c = o->crtc; + if (c) { + for (int i = 0; i < c->numOutputs; i++) { + if (c->outputs[i] == o) { +#ifdef DEBUG + fprintf(stderr, "nxagentDropOutput: output [%s] is in use by crtc [%p], removing it from there\n", o->name, c); +#endif + RRCrtcSet(c, NULL, 0, 0, RR_Rotate_0, 0, NULL); + } + } + } +#ifdef DEBUG + fprintf(stderr, "nxagentDropOutput: destroying output [%s]\n", o->name); +#endif + RROutputDestroy(o); +} + +int nxagentAdjustRandRXinerama(ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + RROutputPtr output; + xRRModeInfo modeInfo; + char name[100]; + int refresh = 60; + int width = nxagentOption(Width); + int height = nxagentOption(Height); + + pScrPriv = rrGetScrPriv(pScreen); + + if (pScrPriv) + { + int i; + int number = 0; + + XineramaScreenInfo *screeninfo = NULL; + + if (nxagentOption(Xinerama)) { + screeninfo = XineramaQueryScreens(nxagentDisplay, &number); +#ifdef DEBUG + if (number) { + fprintf(stderr, "nxagentAdjustRandRXinerama: XineramaQueryScreens() returned [%d] screens:\n", number); + for (int i=0; i < number; i++) { + fprintf(stderr, "nxagentAdjustRandRXinerama: screen_number [%d] x_org [%d] y_org [%d] width [%d] height [%d]\n", screeninfo[i].screen_number, screeninfo[i].x_org, screeninfo[i].y_org, screeninfo[i].width, screeninfo[i].height); + } + + } + else + { + fprintf(stderr, "nxagentAdjustRandRXinerama: XineramaQueryScreens() failed - continuing without Xinerama\n"); + } + } + else + { + fprintf(stderr, "nxagentAdjustRandRXinerama: Xinerama is disabled\n"); +#endif + } + + /* + * if there's no xinerama on the real server or xinerama is + * disabled in nxagent we only report one big screen. Clients + * still see xinerama enabled but it will report only one (big) + * screen. This is consistent with the way rrxinerama always + * behaved. The single PanoramiX/Xinerama extension however + * disables xinerama if only one screen exists. + */ + if (number == 0) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: faking xinerama\n"); + #endif + number = 1; + + if (screeninfo) { + free(screeninfo); + } + if (!(screeninfo = malloc(sizeof(XineramaScreenInfo)))) { + return FALSE; + } + + /* fake a xinerama screeninfo that covers the whole screen */ + screeninfo->screen_number = 0; + screeninfo->x_org = nxagentOption(X); + screeninfo->y_org = nxagentOption(Y); + screeninfo->width = nxagentOption(Width); + screeninfo->height = nxagentOption(Height); + } + +#ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: numCrtcs [%d], numOutputs [%d]\n", pScrPriv->numCrtcs, pScrPriv->numOutputs); + { + Bool rrgetinfo; + + /* + * Convert old RANDR 1.0 data (if any) to current structure. This + * is needed once at the first run of this function. If we don't + * do this here it will be done implicitely later and add mode(s) to + * our crtc(s)! + */ + rrgetinfo = RRGetInfo(pScreen, FALSE); + + fprintf(stderr, "nxagentAdjustRandRXinerama: RRGetInfo returned [%d]\n", rrgetinfo); + } +#else + /* we are not interested in the return code */ + RRGetInfo(pScreen, FALSE); +#endif + +#ifndef NXAGENT_RANDR_XINERAMA_CLIPPING + /* calculate bounding box (outer edges) */ + int bbx2, bbx1, bby1, bby2; + bbx2 = bby2 = 0; + bbx1 = bby1 = INT_MAX; + + for (i = 0; i < number; i++) { + bbx2 = MAX(bbx2, screeninfo[i].x_org + screeninfo[i].width); + bby2 = MAX(bby2, screeninfo[i].y_org + screeninfo[i].height); + bbx1 = MIN(bbx1, screeninfo[i].x_org); + bby1 = MIN(bby1, screeninfo[i].y_org); + } + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: bounding box: left [%d] right [%d] top [%d] bottom [%d]\n", bbx1, bbx2, bby1, bby2); + #endif +#endif + + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: numCrtcs [%d], numOutputs [%d]\n", pScrPriv->numCrtcs, pScrPriv->numOutputs); + #endif + + /* adjust the number of CRTCs to match the number of reported + xinerama screens on the real server */ + while (number != pScrPriv->numCrtcs) { + if (number < pScrPriv->numCrtcs) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: destroying crtc\n"); + #endif + /* first reset the crtc to free possible outputs, then destroy the crtc */ + RRCrtcSet(pScrPriv->crtcs[pScrPriv->numCrtcs - 1], NULL, 0, 0, RR_Rotate_0, 0, NULL); + RRCrtcDestroy(pScrPriv->crtcs[pScrPriv->numCrtcs - 1]); + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: adding crtc\n"); + #endif + RRCrtcCreate(pScreen, NULL); + } + } + + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: numCrtcs [%d], numOutputs [%d]\n", pScrPriv->numCrtcs, pScrPriv->numOutputs); + #endif + + /* set gamma. Currently the only reason for doing this is + preventing the xrandr command from complaining about missing + gamma. */ + for (i = 0; i < pScrPriv->numCrtcs; i++) { + if (pScrPriv->crtcs[i]->gammaSize == 0) { + CARD16 gamma = 0; + RRCrtcGammaSetSize(pScrPriv->crtcs[i], 1); + RRCrtcGammaSet(pScrPriv->crtcs[i], &gamma, &gamma, &gamma); + RRCrtcGammaNotify(pScrPriv->crtcs[i]); + } + } + + /* delete superfluous non-NX outputs */ + for (i = pScrPriv->numOutputs - 1; i >= 0; i--) + if (strncmp(pScrPriv->outputs[i]->name, "NX", 2)) + nxagentDropOutput(pScrPriv->outputs[i]); + + /* at this stage only NX outputs are left - we delete the superfluous ones */ + for (i = pScrPriv->numOutputs - 1; i >= number; i--) + nxagentDropOutput(pScrPriv->outputs[i]); + + /* add and init outputs */ + for (i = 0; i < number; i++) { + if (i >= pScrPriv->numOutputs) { + sprintf(name, "NX%d", i+1); + output = RROutputCreate(pScreen, name, strlen(name), NULL); + /* will be done later + RROutputSetConnection(output, RR_Disconnected); + */ + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: created new output [%s]\n", name); + #endif + } + else + { + output = pScrPriv->outputs[i]; + } + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: adjusting output [%s]\n", pScrPriv->outputs[i]->name); + #endif + RROutputSetCrtcs(output, &(pScrPriv->crtcs[i]), 1); + /* FIXME: Isn't there a function for setting this? */ + output->crtc = pScrPriv->crtcs[i]; + /* FIXME: get SubPixelOrder from real X server */ + RROutputSetSubpixelOrder(output, SubPixelUnknown); + /* FIXME: What is the correct physical size here? */ + RROutputSetPhysicalSize(output, 0, 0); + } + + for (i = 0; i < pScrPriv->numOutputs; i++) { + Bool disable_output = FALSE; + RRModePtr mymode, prevmode; + int new_x, new_y; + unsigned int new_w, new_h; + + /* + if ((nxagentOption(X) < bbx1 || (nxagentOption(X) + width >= bbx2 )) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: output [%d] name [%s]: window has parts outside visible area - width stays unchanged [%d]\n", i, pScrPriv->outputs[i]->name, width); + #endif + new_w = width; + } + + if ((nxagentOption(Y) < bby1 || (nxagentOption(Y) + height >= bby2 ) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: output [%d] name [%s]: window has parts outside visible area - height stays unchanged [%d]\n", i, pScrPriv->outputs[i]->name, height); + #endif + new_h = height; + } + */ + + /* if there's no intersection disconnect the output */ +#ifdef NXAGENT_RANDR_XINERAMA_CLIPPING + disable_output = !intersect(nxagentOption(X), nxagentOption(Y), + width, height, + screeninfo[i].x_org, screeninfo[i].y_org, + screeninfo[i].width, screeninfo[i].height, + &new_x, &new_y, &new_w, &new_h); +#else + disable_output = !intersect_bb(nxagentOption(X), nxagentOption(Y), + width, height, + screeninfo[i].x_org, screeninfo[i].y_org, + screeninfo[i].width, screeninfo[i].height, + bbx1, bby1, bbx2, bby2, + &new_x, &new_y, &new_w, &new_h); +#endif + + /* save previous mode */ + prevmode = pScrPriv->crtcs[i]->mode; + #ifdef DEBUG + if (prevmode) { + fprintf(stderr, "nxagentAdjustRandRXinerama: output [%d] name [%s]: prevmode [%s] ([%p]) refcnt [%d]\n", i, pScrPriv->outputs[i]->name, prevmode->name, (void *)prevmode, prevmode->refcnt); + } else { + fprintf(stderr, "nxagentAdjustRandRXinerama: output [%d] name [%s]: no prevmode\n", i, pScrPriv->outputs[i]->name); + } + #endif + + RROutputSetCrtcs(pScrPriv->outputs[i], &(pScrPriv->crtcs[i]), 1); + + if (disable_output) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: output [%d] name [%s]: no (valid) intersection - disconnecting\n", i, pScrPriv->outputs[i]->name); + #endif + RROutputSetConnection(pScrPriv->outputs[i], RR_Disconnected); + + /* + * Tests revealed that some window managers (e.g. LXDE) also + * take disconnected outputs into account when calculating + * stuff like wallpaper tile size and maximum window + * size. This is problematic when a disconnected output is + * smaller than any of the connected ones. Solution: unset the + * mode of the output's crtc. This also leads to xinerama not + * showing the disconnected head anymore. + */ + if (prevmode) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: removing mode from output [%d] name [%s]\n", i, pScrPriv->outputs[i]->name); + #endif + RROutputSetModes(pScrPriv->outputs[i], NULL, 0, 0); + + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: removing mode from ctrc [%d]\n", i); + #endif + RRCrtcSet(pScrPriv->crtcs[i], NULL, 0, 0, RR_Rotate_0, 1, &(pScrPriv->outputs[i])); + } + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: output [%d] name [%s]: intersection is x [%d] y [%d] width [%d] height [%d]\n", i, pScrPriv->outputs[i]->name, new_x, new_y, new_w, new_h); + #endif + + RROutputSetConnection(pScrPriv->outputs[i], RR_Connected); + + memset(&modeInfo, '\0', sizeof(modeInfo)); + +#ifdef NXAGENT_RANDR_MODE_PREFIX + /* avoid collisions with pre-existing default modes by using a + separate namespace. If we'd simply use XxY we could not + distinguish between pre-existing modes which should stay + and our own modes that should be removed after use. */ + sprintf(name, "nx_%dx%d", new_w, new_h); +#else + sprintf(name, "%dx%d", new_w, new_h); +#endif + + modeInfo.width = new_w; + modeInfo.height = new_h; + modeInfo.hTotal = new_w; + modeInfo.vTotal = new_h; + modeInfo.dotClock = ((CARD32) new_w * (CARD32) new_h * (CARD32) refresh); + modeInfo.nameLength = strlen(name); + + mymode = RRModeGet(&modeInfo, name); + +#ifdef DEBUG + if (mymode) { + fprintf(stderr, "nxagentAdjustRandRXinerama: output [%d] name [%s]: mode [%s] ([%p]) created/received, refcnt [%d]\n", i, pScrPriv->outputs[i]->name, name, (void *) mymode, mymode->refcnt); + } + else + { + /* FIXME: what is the correct behaviour in this case? */ + fprintf(stderr, "nxagentAdjustRandRXinerama: output [%d] name [%s]: mode [%s] creation failed!\n", i, pScrPriv->outputs[i]->name, name); + } +#endif + if (prevmode && mymode == prevmode) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: mymode [%s] ([%p]) == prevmode [%s] ([%p])\n", mymode->name, (void *) mymode, prevmode->name, (void *)prevmode); + #endif + + /* if they are the same RRModeGet() has increased the + refcnt by 1. We decrease it again by calling only + RRModeDestroy() and forget about prevmode */ + RRModeDestroy(mymode); + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: setting mode [%s] ([%p]) refcnt [%d] for output %d [%s]\n", mymode->name, (void *) mymode, mymode->refcnt, i, pScrPriv->outputs[i]->name); + #endif + RROutputSetModes(pScrPriv->outputs[i], &mymode, 1, 0); + + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: setting mode [%s] ([%p]) refcnt [%d] for crtc %d\n", mymode->name, (void *) mymode, mymode->refcnt, i); + #endif + RRCrtcSet(pScrPriv->crtcs[i], mymode, new_x, new_y, RR_Rotate_0, 1, &(pScrPriv->outputs[i])); + + } + } /* if disable_output */ + + /* throw away the mode if otherwise unused. We do not need it + anymore. We call FreeResource() to ensure the system will not + try to free it again on shutdown */ + if (prevmode && prevmode->refcnt == 1) { + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: destroying prevmode [%s]\n", prevmode->name); + #endif + FreeResource(prevmode->mode.id, 0); + } + + RROutputChanged(pScrPriv->outputs[i], TRUE); + RRCrtcChanged(pScrPriv->crtcs[i], TRUE); + } + + /* release allocated memory */ + if (screeninfo) { + free(screeninfo); + screeninfo = NULL; + } + +#ifdef DEBUG + for (i = 0; i < pScrPriv->numCrtcs; i++) { + RRModePtr mode = pScrPriv->crtcs[i]->mode; + if (mode) { + fprintf(stderr, "nxagentAdjustRandRXinerama: crtc [%d] ([%p]) has mode [%s] ([%p]), refcnt [%d] and [%d] outputs:\n", i, (void *) pScrPriv->crtcs[i], pScrPriv->crtcs[i]->mode->name, (void *)pScrPriv->crtcs[i]->mode, pScrPriv->crtcs[i]->mode->refcnt, pScrPriv->crtcs[i]->numOutputs); + } + else + { + fprintf(stderr, "nxagentAdjustRandRXinerama: crtc [%d] ([%p]) has no mode and [%d] outputs:\n", i, (void *) pScrPriv->crtcs[i], pScrPriv->crtcs[i]->numOutputs); + } + + if (pScrPriv->crtcs[i]->numOutputs > 0) + for (int j=0; j < pScrPriv->crtcs[i]->numOutputs; j++) + fprintf(stderr, "nxagentAdjustRandRXinerama: output [%d] name [%s]->crtc=[%p]\n", j, pScrPriv->crtcs[i]->outputs[j]->name, (void *)pScrPriv->crtcs[i]->outputs[j]->crtc); + } +#endif + + pScrPriv -> lastSetTime = currentTime; + + pScrPriv->changed = TRUE; + pScrPriv->configChanged = TRUE; + } + + /* FIXME: adjust maximum screen size according to remote randr/xinerama setup */ + + #ifdef DEBUG + fprintf(stderr, "nxagentAdjustRandRXinerama: Min %dx%d, Max %dx%d \n", pScrPriv->minWidth, pScrPriv->minHeight, pScrPriv->maxWidth, pScrPriv->maxHeight); + #endif + + return TRUE; +} + +void nxagentSaveAreas(PixmapPtr pPixmap, RegionPtr prgnSave, int xorg, int yorg, WindowPtr pWin) +{ + PixmapPtr pVirtualPixmap; + nxagentPrivPixmapPtr pPrivPixmap; + XlibGC gc; + XGCValues values; + int i; + int xSrc, ySrc, xDst, yDst, w, h; + int nRects; + int size; + BoxPtr pBox; + XRectangle *pRects; + BoxRec extents; + RegionRec cleanRegion; + + miBSWindowPtr pBackingStore = (miBSWindowPtr) pWin -> backStorage; + + pVirtualPixmap = nxagentVirtualPixmap(pPixmap); + + pPrivPixmap = nxagentPixmapPriv(pPixmap); + + pPrivPixmap -> isBackingPixmap = 1; + + fbCopyWindowProc(&pWin -> drawable, &pVirtualPixmap -> drawable, 0, RegionRects(prgnSave), + RegionNumRects(prgnSave), xorg, yorg, FALSE, FALSE, 0, 0); + + values.subwindow_mode = IncludeInferiors; + + gc = XCreateGC(nxagentDisplay, nxagentWindow(screenInfo.screens[0]->root), GCSubwindowMode, &values); + + /* + * Initialize to the corrupted region. + * Coordinates are relative to the window. + */ + + RegionInit(&cleanRegion, NullBox, 1); + + RegionCopy(&cleanRegion, nxagentCorruptedRegion((DrawablePtr) pWin)); + + /* + * Subtract the corrupted region from the saved region. + */ + + RegionSubtract(&pBackingStore -> SavedRegion, &pBackingStore -> SavedRegion, &cleanRegion); + + /* + * Translate the corrupted region. Coordinates + * are relative to the backing store pixmap. + */ + + RegionTranslate(&cleanRegion, -pBackingStore -> x, -pBackingStore -> y); + + /* + * Compute the clean region to be saved: subtract + * the corrupted region from the region to be saved. + */ + + RegionSubtract(&cleanRegion, prgnSave, &cleanRegion); + + nRects = RegionNumRects(&cleanRegion); + size = nRects * sizeof(*pRects); + pRects = (XRectangle *) malloc(size); + pBox = RegionRects(&cleanRegion); + + for (i = nRects; i-- > 0;) + { + pRects[i].x = pBox[i].x1; + pRects[i].y = pBox[i].y1; + pRects[i].width = pBox[i].x2 - pBox[i].x1; + pRects[i].height = pBox[i].y2 - pBox[i].y1; + } + + XSetClipRectangles(nxagentDisplay, gc, 0, 0, pRects, nRects, Unsorted); + + free((char *) pRects); + + extents = *RegionExtents(&cleanRegion); + + RegionUninit(&cleanRegion); + + xDst = extents.x1; + yDst = extents.y1; + +/* + * Left here the wrong solution. The window could be not + * configured yet on the real X, whilst the x and y in the + * WindowRec are the new coordinates. The right solution + * is the other, as it is independent from the window + * coordinates. + * + * xSrc = xDst + xorg - pWin -> drawable.x; + * ySrc = yDst + yorg - pWin -> drawable.y; + */ + + xSrc = xDst + pBackingStore -> x; + ySrc = yDst + pBackingStore -> y; + + w = extents.x2 - extents.x1; + h = extents.y2 - extents.y1; + + XCopyArea(nxagentDisplay, nxagentWindow(pWin), nxagentPixmap(pPixmap), gc, + xSrc, ySrc, w, h, xDst, yDst); + + nxagentAddItemBSPixmapList(nxagentPixmap(pPixmap), pPixmap, pWin, + pBackingStore -> x, pBackingStore -> y); + + #ifdef TEST + fprintf(stderr,"nxagentSaveAreas: Added pixmap [%p] with id [%d] on window [%p] to BSPixmapList.\n", + (void *) pPixmap, nxagentPixmap(pPixmap), (void *) pWin); + #endif + + XFreeGC(nxagentDisplay, gc); + + return; +} + +void nxagentRestoreAreas(PixmapPtr pPixmap, RegionPtr prgnRestore, int xorg, + int yorg, WindowPtr pWin) +{ + PixmapPtr pVirtualPixmap; + RegionPtr clipRegion; + XlibGC gc; + XGCValues values; + int i; + int xSrc, ySrc, xDst, yDst, w, h; + int nRects; + int size; + BoxPtr pBox; + XRectangle *pRects; + BoxRec extents; + miBSWindowPtr pBackingStore; + + /* + * Limit the area to restore to the + * root window size. + */ + + RegionIntersect(prgnRestore, prgnRestore, + &pWin -> drawable.pScreen -> root -> winSize); + + pBackingStore = (miBSWindowPtr) pWin -> backStorage; + + pVirtualPixmap = nxagentVirtualPixmap(pPixmap); + + fbCopyWindowProc(&pVirtualPixmap -> drawable, &pWin -> drawable, 0, RegionRects(prgnRestore), + RegionNumRects(prgnRestore), -xorg, -yorg, FALSE, FALSE, 0, 0); + + values.subwindow_mode = ClipByChildren; + + gc = XCreateGC(nxagentDisplay, nxagentWindow(screenInfo.screens[0]->root), GCSubwindowMode, &values); + + /* + * Translate the reference point to the origin of the window. + */ + + RegionTranslate(prgnRestore, + -pWin -> drawable.x - pWin -> borderWidth, + -pWin -> drawable.y - pWin -> borderWidth); + + clipRegion = prgnRestore; + + if (nxagentDrawableStatus((DrawablePtr) pPixmap) == NotSynchronized) + { + clipRegion = RegionCreate(NullBox, 1); + + RegionCopy(clipRegion, + nxagentCorruptedRegion((DrawablePtr) pPixmap)); + + /* + * Translate the reference point to the origin of the window. + */ + + RegionTranslate(clipRegion, + pBackingStore -> x, pBackingStore -> y); + + RegionIntersect(clipRegion, prgnRestore, clipRegion); + + /* + * Subtract the corrupted region from the saved areas. + * miBSRestoreAreas will return the exposure region. + */ + + RegionSubtract(&pBackingStore->SavedRegion, + &pBackingStore->SavedRegion, clipRegion); + + /* + * Store the corrupted region to send expose later. + */ + + if (nxagentRemoteExposeRegion != NULL) + { + RegionTranslate(clipRegion, pWin -> drawable.x, pWin -> drawable.y); + + RegionUnion(nxagentRemoteExposeRegion, nxagentRemoteExposeRegion, clipRegion); + + RegionTranslate(clipRegion, -pWin -> drawable.x, -pWin -> drawable.y); + } + + /* + * Compute the region to be restored. + */ + + RegionSubtract(clipRegion, prgnRestore, clipRegion); + } + + nRects = RegionNumRects(clipRegion); + size = nRects * sizeof(*pRects); + pRects = (XRectangle *) malloc(size); + pBox = RegionRects(clipRegion); + + for (i = nRects; i-- > 0;) + { + pRects[i].x = pBox[i].x1; + pRects[i].y = pBox[i].y1; + pRects[i].width = pBox[i].x2 - pBox[i].x1; + pRects[i].height = pBox[i].y2 - pBox[i].y1; + } + + XSetClipRectangles(nxagentDisplay, gc, 0, 0, pRects, nRects, Unsorted); + + free(pRects); + + extents = *RegionExtents(clipRegion); + + xDst = extents.x1; + yDst = extents.y1; + + xSrc = xDst - xorg + pWin -> drawable.x; + ySrc = yDst - yorg + pWin -> drawable.y; + + w = extents.x2 - extents.x1; + h = extents.y2 - extents.y1; + + nxagentFlushConfigureWindow(); + + XCopyArea(nxagentDisplay, nxagentPixmap(pPixmap), nxagentWindow(pWin), gc, + xSrc, ySrc, w, h, xDst, yDst); + + XFreeGC(nxagentDisplay, gc); + + if (clipRegion != NULL && clipRegion != prgnRestore) + { + RegionDestroy(clipRegion); + } + + /* + * Restore the reference point to the origin of the screen. + */ + + RegionTranslate(prgnRestore, + pWin -> drawable.x - pWin -> borderWidth, + pWin -> drawable.y + pWin -> borderWidth); + + return; +} + +void nxagentSetWMNormalHints(int screen) +{ + XSizeHints sizeHints; + + /* + * Change agent window size and size hints. + */ + + sizeHints.flags = PPosition | PMinSize | PMaxSize; + sizeHints.x = nxagentOption(X); + sizeHints.y = nxagentOption(Y); + + sizeHints.min_width = MIN_NXAGENT_WIDTH; + sizeHints.min_height = MIN_NXAGENT_HEIGHT; + + sizeHints.width = nxagentOption(Width); + sizeHints.height = nxagentOption(Height); + + if (nxagentOption(DesktopResize) == 1) + { + sizeHints.max_width = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + sizeHints.max_height = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + } + else + { + sizeHints.max_width = nxagentOption(RootWidth); + sizeHints.max_height = nxagentOption(RootHeight); + } + + if (nxagentUserGeometry.flag & XValue || nxagentUserGeometry.flag & YValue) + { + sizeHints.flags |= USPosition; + } + + if (nxagentUserGeometry.flag & WidthValue || nxagentUserGeometry.flag & HeightValue) + { + sizeHints.flags |= USSize; + } + + XSetWMNormalHints(nxagentDisplay, nxagentDefaultWindows[screen], &sizeHints); +} + +void nxagentShadowAdaptToRatio(void) +{ + XSizeHints sizeHints; + ScreenPtr pScreen; + RegionRec region; + BoxRec box; + + pScreen = screenInfo.screens[0]; + + nxagentShadowSetRatio(nxagentOption(Width) * 1.0 / nxagentShadowWidth, + nxagentOption(Height) * 1.0 / nxagentShadowHeight); + + nxagentShadowCreateMainWindow(pScreen, screenInfo.screens[0]->root, nxagentShadowWidth, nxagentShadowHeight); + + sizeHints.max_width = WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + sizeHints.max_height = HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)); + + sizeHints.flags = PMaxSize; + + XSetWMNormalHints(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum], &sizeHints); + + box.x1 = 0; + box.y1 = 0; + box.x2 = nxagentShadowPixmapPtr -> drawable.width; + box.y2 = nxagentShadowPixmapPtr -> drawable.height; + + RegionInit(®ion, &box, 1); + + nxagentMarkCorruptedRegion((DrawablePtr)nxagentShadowPixmapPtr, ®ion); + + RegionUninit(®ion); +} + +void nxagentPrintGeometry() +{ + int i; + + for (i = 0; i < screenInfo.numScreens; i++) + { + if (nxagentPrintGeometryFlags && (1 << i)) + { + fprintf(stderr, "Info: Screen [%d] resized to geometry [%dx%d] " + "fullscreen [%d].\n", i, screenInfo.screens[i] -> width, + screenInfo.screens[i] -> height, + nxagentOption(Fullscreen)); + } + } + + nxagentPrintGeometryFlags = 0; +} + +#ifdef DUMP + +void nxagentShowPixmap(PixmapPtr pPixmap, int x, int y, int width, int height) +{ + static int init = 1; + static Display *shadow; + static Window win; + + XlibGC gc; + XGCValues value; + XImage *image; + WindowPtr pWin = screenInfo.screens[0]->root; + unsigned int format; + int depth, pixmapWidth, pixmapHeight, length; + char *data; + + depth = pPixmap -> drawable.depth; + pixmapWidth = pPixmap -> drawable.width; + pixmapHeight = pPixmap -> drawable.height; + format = (depth == 1) ? XYPixmap : ZPixmap; + + if (init) + { + shadow = XOpenDisplay("localhost:0"); + + if (shadow == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentShowPixmap: WARNING! Shadow display not opened.\n"); + #endif + + return; + } + + init = False; + } + + if (win == 0) + { + win = XCreateSimpleWindow(shadow, DefaultRootWindow(shadow), 0, 0, + width, height, 0, 0xFFCC33, 0xFF); + + XSelectInput(shadow, win, StructureNotifyMask); + + XMapWindow(shadow, win); + + for(;;) + { + XEvent e; + + XNextEvent(shadow, &e); + + if (e.type == MapNotify) + { + break; + } + } + } + else + { + XResizeWindow(nxagentDisplay, win, width, height); + XRaiseWindow(nxagentDisplay, win); + } + + length = nxagentImageLength(width, height, format, 0, depth); + + if ((data = malloc(length)) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentShowPixmap: malloc failed.\n"); + #endif + + return; + } + +/* +FIXME + image = XGetImage(nxagentDisplay, nxagentPixmap(pPixmap), x, y, + width, height, AllPlanes, format); +*/ + + image = XGetImage(nxagentDisplay, RootWindow(nxagentDisplay, 0), 0, 0, + width, height, AllPlanes, format); + + if (image == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentShowPixmap: XGetImage failed.\n"); + #endif + + if (data) + { + free(data); + } + + return; + } + + fbGetImage((DrawablePtr)pPixmap, 0, 0, + width, height, format, AllPlanes, data); + + memcpy(image -> data, data, length); + + value.foreground = 0xffffff; + value.background = 0x000000; + value.plane_mask = 0xffffff; + value.fill_style = FillSolid; + + gc = XCreateGC(shadow, win, GCBackground | + GCForeground | GCFillStyle | GCPlaneMask, &value); + + XSync(shadow, 0); + + NXCleanImage(image); + + XPutImage(shadow, win, gc, image, 0, 0, 0, 0, width, height); + + XFlush(shadow); + + XFreeGC(shadow, gc); + + if (image != NULL) + { + XDestroyImage(image); + } + + if (data != NULL) + { + free(data); + } + +/* +FIXME + if (win != NULL) + { + XDestroyWindow(shadow, win); + } +*/ +} + +void nxagentFbRestoreArea(PixmapPtr pPixmap, WindowPtr pWin, int xSrc, int ySrc, int width, + int height, int xDst, int yDst) +{ + Display *shadow; + + XlibGC gc; + XGCValues value; + XImage *image; + unsigned int format; + int depth, pixmapWidth, pixmapHeight, length; + char *data = NULL; + Visual *pVisual; + + depth = pPixmap -> drawable.depth; + pixmapWidth = pPixmap -> drawable.width; + pixmapHeight = pPixmap -> drawable.height; + format = (depth == 1) ? XYPixmap : ZPixmap; + + shadow = nxagentDisplay; + + length = nxagentImageLength(width, height, format, 0, depth); + + if ((data = malloc(length)) == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentFbRestoreArea: malloc failed.\n"); + #endif + + return; + } +/* + image = XGetImage(nxagentDisplay, nxagentPixmap(pPixmap), xSrc, ySrc, + width, height, AllPlanes, format); +*/ + + if (image == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentFbRestoreArea: XGetImage failed.\n"); + #endif + + if (data) + { + free(data); + } + + return; + } + + fbGetImage((DrawablePtr)pPixmap, xSrc, ySrc, + width, height, format, AllPlanes, data); + +/* +FIXME +*/ + pVisual = nxagentImageVisual((DrawablePtr) pPixmap, depth); + + if (pVisual == NULL) + { + #ifdef WARNING + fprintf(stderr, "nxagentFbRestoreArea: WARNING! Visual not found. Using default visual.\n"); + #endif + + pVisual = nxagentVisuals[nxagentDefaultVisualIndex].visual; + } + + image = XCreateImage(nxagentDisplay, pVisual, + depth, format, 0, (char *) data, + width, height, BitmapPad(nxagentDisplay), + nxagentImagePad(width, format, 0, depth)); +/* +FIXME + memcpy(image -> data, data, length); +*/ + + fprintf(stderr, "nxagentFbRestoreArea: Cleaning %d bytes of image.\n", length); + + value.foreground = 0xffffff; + value.background = 0x000000; + value.plane_mask = 0xffffff; + value.fill_style = FillSolid; + value.function = GXcopy; + + gc = XCreateGC(shadow, nxagentWindow(screenInfo.screens[0]->root), GCBackground | + GCForeground | GCFillStyle | GCPlaneMask | GCFunction, &value); + + NXCleanImage(image); + + XPutImage(shadow, nxagentWindow(pWin), gc, image, 0, 0, xDst, yDst, width, height); + +/* +FIXME +*/ + XFlush(shadow); + + XFreeGC(shadow, gc); + + if (image) + { + XDestroyImage(image); + } + +/* +FIXME + if (data) + { + free(data); + } +*/ +} + +#endif diff --git a/nx-X11/programs/Xserver/hw/nxagent/Screen.h b/nx-X11/programs/Xserver/hw/nxagent/Screen.h new file mode 100644 index 000000000..3df586fa8 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Screen.h @@ -0,0 +1,149 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Screen_H__ +#define __Screen_H__ + +#include "scrnintstr.h" + +#define MIN_NXAGENT_WIDTH 80 +#define MIN_NXAGENT_HEIGHT 60 +#define NXAGENT_FRAME_WIDTH 2000 + +#define nxagentSetPrintGeometry(screen) \ + nxagentPrintGeometryFlags = (1 << (screen)); + +extern int nxagentClients; + +extern int nxagentAutoDisconnectTimeout; + +extern ScreenPtr nxagentDefaultScreen; + +extern Pixmap nxagentPixmapLogo; + +extern Window nxagentIconWindow; + +extern Window nxagentFullscreenWindow; + +extern RegionRec nxagentShadowUpdateRegion; + +extern WindowPtr nxagentShadowWindowPtr; + +extern int nxagentShadowResize; + +extern short nxagentShadowUid; + +void nxagentSetScreenInfo(ScreenInfo *screenInfo); +void nxagentSetPixmapFormats(ScreenInfo *screenInfo); + +void nxagentPrintGeometry(); + +extern Window nxagentDefaultWindows[MAXSCREENS]; +extern Window nxagentInputWindows[MAXSCREENS]; +extern Window nxagentScreenSaverWindows[MAXSCREENS]; + +#ifdef VIEWPORT_FRAME + +void nxagentInitViewportFrame(ScreenPtr pScreen, WindowPtr pRootWin); + +#else /* #ifdef VIEWPORT_FRAME */ + +#define nxagentInitViewportFrame(pScreen, pRootWin) + +#endif /* #ifdef VIEWPORT_FRAME */ + +Bool nxagentOpenScreen(ScreenPtr pScreen, + int argc, char *argv[]); + +Bool nxagentCloseScreen(ScreenPtr pScreen); + +#define nxagentScreen(window) nxagentDefaultScreen + +extern int nxagentBitsPerPixel(int depth); + +void nxagentSetScreenSaverTime(void); + +void nxagentMinimizeFromFullScreen(ScreenPtr pScreen); + +void nxagentMaximizeToFullScreen(ScreenPtr pScreen); + +Window nxagentCreateIconWindow(void); + +Bool nxagentMagicPixelZone(int x, int y); + +Bool nxagentResizeScreen(ScreenPtr pScreen, int width, int height, + int mmWidth, int mmHeight); + +int nxagentChangeScreenConfig(int screen, int width, int height, int mmWidth, int mmHeight); + +int nxagentAdjustRandRXinerama(ScreenPtr pScreen); + +extern Bool nxagentReconnectScreen(void *p0); + +void nxagentSaveAreas(PixmapPtr pPixmap, RegionPtr prgnSave, int xorg, int yorg, WindowPtr pWin); + +void nxagentRestoreAreas(PixmapPtr pPixmap, RegionPtr prgnRestore, int xorg, int yorg, WindowPtr pWin); + +extern int monitorResolution; + +int nxagentShadowCreateMainWindow( ScreenPtr pScreen, WindowPtr pWin,int width, int height); + +int nxagentShadowSendUpdates(int *); + +int nxagentShadowPoll(PixmapPtr, GCPtr, unsigned char, int, int, char *, int *, int *); + +void nxagentShadowSetWindowsSize(void); + +void nxagentSetWMNormalHints(int); + +void nxagentShadowSetRatio(float, float); + +/* + * Change window settings to adapt to a ratio. + */ + +extern void nxagentShadowAdaptToRatio(void); + +/* + * The pixmap shadowing the real frame buffer. + */ + +extern PixmapPtr nxagentShadowPixmapPtr; + +#endif /* __Screen_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Splash.c b/nx-X11/programs/Xserver/hw/nxagent/Splash.c new file mode 100644 index 000000000..0d3c2ff22 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Splash.c @@ -0,0 +1,424 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "windowstr.h" +#include "scrnintstr.h" + +#ifdef _XSERVER64 + +#include "Agent.h" + +#define GC XlibGC + +#endif /* _XSERVER64 */ + +#include "Xlib.h" +#include "Xutil.h" + +#include "Display.h" +#include "Splash.h" +#include "Screen.h" +#include "Windows.h" +#include "Atoms.h" +#include "Trap.h" +#include "Init.h" + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Colors used to paint the splash screen. + */ + +int nxagentLogoDepth; +int nxagentLogoWhite; +int nxagentLogoRed; +int nxagentLogoBlack; +int nxagentLogoGray; + +void nxagentPaintLogo(Window win, GC gc, int scale, int width, int height); + +/* + * From Screen.c. + */ + +extern Atom nxagentWMStart; + +/* + * From Clipboard.c. + */ + +extern Atom serverCutProperty; + +int nxagentShowSplashWindow(Window parentWindow) +{ + XWindowAttributes getAttributes; + XWindowChanges values; + XSetWindowAttributes attributes; + GC gc; + + #ifdef TEST + fprintf(stderr, "nxagentShowSplash: Got called.\n"); + #endif + + #ifdef NXAGENT_TIMESTAMP + { + extern unsigned long startTime; + + fprintf(stderr, "nxagentShowSplash: Initializing splash start at [%d] milliseconds.\n", + GetTimeInMillis() - startTime); + } + #endif + + XSetSelectionOwner(nxagentDisplay, nxagentWMStart, None, CurrentTime); + + nxagentWMPassed = False; + + /* + * This would cause a GetWindowAttributes and a + * GetGeometry (asynchronous) reply. We use instead + * the geometry requested by the user for the agent + * window. + * + * XGetWindowAttributes(nxagentDisplay, parentWindow, &getAttributes); + */ + + /* + * During reconnection we draw the splash over + * the default window and not over the root + * window because it would be hidden by other + * windows. + */ + + if (nxagentReconnectTrap) + { + getAttributes.x = nxagentOption(RootX); + getAttributes.y = nxagentOption(RootY); + } + else + { + getAttributes.x = 0; + getAttributes.y = 0; + } + + getAttributes.width = nxagentOption(RootWidth); + getAttributes.height = nxagentOption(RootHeight); + + #ifdef TEST + fprintf(stderr, "nxagentShowSplash: Going to create new splash window.\n"); + #endif + + nxagentSplashWindow = + XCreateSimpleWindow(nxagentDisplay, + parentWindow, + getAttributes.x, getAttributes.y, + getAttributes.width, getAttributes.height, + 0, + WhitePixel (nxagentDisplay, 0), + BlackPixel (nxagentDisplay, 0)); + + #ifdef TEST + fprintf(stderr, "nxagentShowSplash: Created new splash window with id [%ld].\n", + nxagentSplashWindow); + #endif + + gc = XCreateGC(nxagentDisplay, nxagentSplashWindow, 0, NULL); + nxagentPaintLogo(nxagentSplashWindow, gc, 1, getAttributes.width, getAttributes.height); + XMapRaised (nxagentDisplay, nxagentSplashWindow); + values.stack_mode = Above; + XConfigureWindow(nxagentDisplay, nxagentSplashWindow, CWStackMode, &values); + attributes.override_redirect = True; + XChangeWindowAttributes(nxagentDisplay, nxagentSplashWindow, CWOverrideRedirect, &attributes); + XFreeGC(nxagentDisplay, gc); + + #ifdef NXAGENT_TIMESTAMP + { + extern unsigned long startTime; + fprintf(stderr, "nxagentShowSplash: Splash ends [%d] milliseconds.\n", + GetTimeInMillis() - startTime); + } + #endif + + return True; +} + +void nxagentPaintLogo(Window win, GC gc, int scale, int width, int height) +{ + XPoint rect[4]; + int w, h, c, w2, h2; + + /* + * Show only X2GO Logo when running as X2Go Agent + */ + if(! nxagentX2go) + { + nxagentPixmapLogo = 0L; + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagenShowtLogo: Got called.\n"); + #endif + + #ifdef NXAGENT_LOGO_DEBUG + fprintf(stderr, "nxagentPaintLogo: begin\n"); + fprintf(stderr, "nxagentPaintLogo: gen params are: w=%d h=%d d=%d r=%x w=%x b=%x\n",width, height, + nxagentLogoDepth, nxagentLogoRed, + nxagentLogoWhite, nxagentLogoBlack); + #endif + + w = width/scale; + h = height/scale; + + w2 = w/2; + h2 = h/2; + + if (height > width) + { + c = w/30; + } + else + { + c = w/48; + } + + rect[0].x = 0; rect[0].y = 0; + rect[1].x = 0; rect[1].y = h; + rect[2].x = w; rect[2].y = h; + rect[3].x = w; rect[3].y = 0; + + XSetFunction(nxagentDisplay, gc, GXcopy); + XSetFillStyle(nxagentDisplay, gc, FillSolid); + XSetForeground(nxagentDisplay, gc, nxagentLogoBlack); + XSetBackground(nxagentDisplay, gc, nxagentLogoRed); + + nxagentPixmapLogo = XCreatePixmap(nxagentDisplay, win, width, height, nxagentLogoDepth); + + if (!nxagentPixmapLogo) + { + return; + } + + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + #ifdef NXAGENT_LOGO_DEBUG + fprintf(stderr, "filled first poly\n"); + #endif + + XSetForeground(nxagentDisplay, gc, nxagentLogoRed); + XSetBackground(nxagentDisplay, gc, nxagentLogoWhite); + + /* + * Draw X2GO Logo + */ + + /* + * Begin 'X'. + */ + + XSetForeground(nxagentDisplay, gc, nxagentLogoGray); + XSetBackground(nxagentDisplay, gc, nxagentLogoWhite); + rect[0].x = w2-7*c; rect[0].y = h2-5*c; + rect[1].x = w2-8*c; rect[1].y = h2-5*c; + rect[2].x = w2-4*c; rect[2].y = h2+3*c; + rect[3].x = w2-3*c; rect[3].y = h2+3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2-4*c; rect[0].y = h2-5*c; + rect[1].x = w2-3*c; rect[1].y = h2-5*c; + rect[2].x = w2-7*c; rect[2].y = h2+3*c; + rect[3].x = w2-8*c; rect[3].y = h2+3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + /* + * End 'X'. + */ + + /* + * Start '2'. + */ + + rect[0].x = w2-2*c; rect[0].y = h2-5*c; + rect[1].x = w2-1*c; rect[1].y = h2-5*c; + rect[2].x = w2-1*c; rect[2].y = h2-3*c; + rect[3].x = w2-2*c; rect[3].y = h2-3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2-2*c; rect[0].y = h2-5*c; + rect[1].x = w2+2*c; rect[1].y = h2-5*c; + rect[2].x = w2+2*c; rect[2].y = h2-4*c; + rect[3].x = w2-2*c; rect[3].y = h2-4*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+1*c; rect[0].y = h2-5*c; + rect[1].x = w2+2*c; rect[1].y = h2-5*c; + rect[2].x = w2+2*c; rect[2].y = h2-2*c; + rect[3].x = w2+1*c; rect[3].y = h2-2*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+2*c; rect[0].y = h2-2*c; + rect[1].x = w2+1*c; rect[1].y = h2-2*c; + rect[2].x = w2-2*c; rect[2].y = h2+2*c; + rect[3].x = w2-1*c; rect[3].y = h2+2*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + + rect[0].x = w2-2*c; rect[0].y = h2+2*c; + rect[1].x = w2+2*c; rect[1].y = h2+2*c; + rect[2].x = w2+2*c; rect[2].y = h2+3*c; + rect[3].x = w2-2*c; rect[3].y = h2+3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + /* + * End '2'. + */ + + /* + * Start 'G'. + */ + + rect[0].x = w2+3*c; rect[0].y = h2-5*c; + rect[1].x = w2+7*c; rect[1].y = h2-5*c; + rect[2].x = w2+7*c; rect[2].y = h2-4*c; + rect[3].x = w2+3*c; rect[3].y = h2-4*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+3*c; rect[0].y = h2-5*c; + rect[1].x = w2+4*c; rect[1].y = h2-5*c; + rect[2].x = w2+4*c; rect[2].y = h2+3*c; + rect[3].x = w2+3*c; rect[3].y = h2+3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+3*c; rect[0].y = h2+2*c; + rect[1].x = w2+7*c; rect[1].y = h2+2*c; + rect[2].x = w2+7*c; rect[2].y = h2+3*c; + rect[3].x = w2+3*c; rect[3].y = h2+3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+6*c; rect[0].y = h2-5*c; + rect[1].x = w2+7*c; rect[1].y = h2-5*c; + rect[2].x = w2+7*c; rect[2].y = h2-3*c; + rect[3].x = w2+6*c; rect[3].y = h2-3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+6*c; rect[0].y = h2-0*c; + rect[1].x = w2+7*c; rect[1].y = h2-0*c; + rect[2].x = w2+7*c; rect[2].y = h2+3*c; + rect[3].x = w2+6*c; rect[3].y = h2+3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+5*c; rect[0].y = h2-1*c; + rect[1].x = w2+7*c; rect[1].y = h2-1*c; + rect[2].x = w2+7*c; rect[2].y = h2+0*c; + rect[3].x = w2+5*c; rect[3].y = h2+0*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + /* + * End 'G'. + */ + + /* + * Start 'O'. + */ + + rect[0].x = w2+8*c; rect[0].y = h2-5*c; + rect[1].x = w2+12*c; rect[1].y = h2-5*c; + rect[2].x = w2+12*c; rect[2].y = h2-4*c; + rect[3].x = w2+8*c; rect[3].y = h2-4*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+8*c; rect[0].y = h2+3*c; + rect[1].x = w2+12*c; rect[1].y = h2+3*c; + rect[2].x = w2+12*c; rect[2].y = h2+2*c; + rect[3].x = w2+8*c; rect[3].y = h2+2*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+8*c; rect[0].y = h2-5*c; + rect[1].x = w2+9*c; rect[1].y = h2-5*c; + rect[2].x = w2+9*c; rect[2].y = h2+3*c; + rect[3].x = w2+8*c; rect[3].y = h2+3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + rect[0].x = w2+11*c; rect[0].y = h2-5*c; + rect[1].x = w2+12*c; rect[1].y = h2-5*c; + rect[2].x = w2+12*c; rect[2].y = h2+3*c; + rect[3].x = w2+11*c; rect[3].y = h2+3*c; + XFillPolygon(nxagentDisplay, nxagentPixmapLogo, gc, rect, 4, Convex, CoordModeOrigin); + + /* + * End 'O'. + */ + + + XSetWindowBackgroundPixmap(nxagentDisplay, win, nxagentPixmapLogo); + + #ifdef NXAGENT_LOGO_DEBUG + fprintf(stderr, "nxagentPaintLogo: end\n"); + #endif +} + +void nxagentRemoveSplashWindow(WindowPtr pWin) +{ + if (nxagentReconnectTrap) return; + + #ifdef TEST + fprintf(stderr, "nxagentRemoveSplashWindow: Destroying the splash window.\n"); + #endif + + if (!nxagentWMPassed) + { + XSetSelectionOwner(nxagentDisplay, nxagentWMStart, + nxagentDefaultWindows[0], CurrentTime); + + nxagentWMPassed = True; + } + + if (nxagentSplashWindow != None) + { + XDestroyWindow(nxagentDisplay, nxagentSplashWindow); + + nxagentSplashWindow = None; + nxagentRefreshWindows(screenInfo.screens[0]->root); + + #ifdef TEST + fprintf(stderr, "nxagentRemoveSplashWindow: setting the ownership of %s (%d) on window 0x%lx\n", + "NX_CUT_BUFFER_SERVER", (int)serverCutProperty, nxagentWindow(screenInfo.screens[0]->root)); + #endif + + XSetSelectionOwner(nxagentDisplay, serverCutProperty, + nxagentWindow(screenInfo.screens[0]->root), CurrentTime); + } + + if (nxagentPixmapLogo) + { + XFreePixmap(nxagentDisplay, nxagentPixmapLogo); + + nxagentPixmapLogo = (Pixmap) 0; + } +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Splash.h b/nx-X11/programs/Xserver/hw/nxagent/Splash.h new file mode 100644 index 000000000..444f1eed0 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Splash.h @@ -0,0 +1,54 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Splash_H__ +#define __Splash_H__ + +#include "Windows.h" +#include "X11/Xdmcp.h" +#include <nx/NXalert.h> + +#define XDM_TIMEOUT 20000 + +extern xdmcp_states XdmcpState; +extern int XdmcpTimeOutRtx; +extern int XdmcpStartTime; +extern int nxagentXdmcpUp; + +extern int nxagentLogoDepth; +extern int nxagentLogoWhite; +extern int nxagentLogoRed; +extern int nxagentLogoBlack; +extern int nxagentLogoGray; + +extern Window nxagentSplashWindow; + +extern int nxagentWMPassed; + +extern int nxagentShowSplashWindow(Window); + +extern void nxagentRemoveSplashWindow(WindowPtr pWin); + +#endif /* __Splash_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Split.c b/nx-X11/programs/Xserver/hw/nxagent/Split.c new file mode 100644 index 000000000..9b9691b02 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Split.c @@ -0,0 +1,1256 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "gcstruct.h" + +#include "Agent.h" +#include "Display.h" +#include "Drawable.h" +#include "Events.h" +#include "GCs.h" + +#include "compext/Compext.h" + + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * This should be a macro but for now + * we make it a real function to log + * a warning in the logs. + */ + +DrawablePtr nxagentSplitDrawable(DrawablePtr pDrawable) +{ + if (pDrawable -> type == DRAWABLE_PIXMAP && + nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) + { + #ifdef TEST + fprintf(stderr, "nxagentSplitDrawable: WARNING! The drawable at [%p] is " + "virtual. Assuming real at [%p].\n", (void *) pDrawable, + (void *) nxagentRealPixmap((PixmapPtr) pDrawable)); + #endif + + return (DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable); + } + else + { + return pDrawable; + } +} + +void nxagentInitSplitResources() +{ + int resource; + + #ifdef TEST + fprintf(stderr, "nxagentInitSplitResources: Initializing the split resources.\n"); + #endif + + for (resource = 0; resource < NXNumberOfResources; resource++) + { + SplitResourcePtr pResource = &nxagentSplitResources[resource]; + + pResource -> pending = 0; + pResource -> commit = 0; + pResource -> split = NXNoResource; + pResource -> unpack = NXNoResource; + pResource -> drawable = NULL; + pResource -> region = NullRegion; + pResource -> gc = NULL; + } +} + +SplitResourcePtr nxagentAllocSplitResource() +{ + int resource; + + SplitResourcePtr pResource; + + for (;;) + { + resource = NXAllocSplit(nxagentDisplay, NXAnyResource); + + if (resource != NXNoResource) + { + #ifdef TEST + fprintf(stderr, "nxagentAllocSplitResource: Reserving resource [%d] for the next split.\n", + resource); + #endif + + break; + } + else + { + #ifdef PANIC + fprintf(stderr, "nxagentAllocSplitResource: PANIC! No more resources for the next split.\n"); + #endif +/* +FIXME: Must deal with the case all resources are exausted. +*/ + FatalError("nxagentAllocSplitResource: PANIC! No more resources for the next split.\n"); + } + } + + pResource = &nxagentSplitResources[resource]; + + if (pResource -> pending != 0 || pResource -> split != NXNoResource || + pResource -> unpack != NXNoResource || pResource -> drawable != NULL || + pResource -> region != NullRegion || pResource -> commit != 0 || + pResource -> gc != NULL) + { + /* + * This is really an unrecoverable error. + */ + + #ifdef PANIC + fprintf(stderr, "nxagentAllocSplitResource: PANIC! Invalid record for resource [%d] with " + "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n", + resource, pResource -> pending, pResource -> split, pResource -> unpack, + (void *) pResource -> drawable, (void *) pResource -> region, + pResource -> commit, (void *) pResource -> gc); + #endif + + FatalError("nxagentAllocSplitResource: PANIC! Invalid record for resource [%d] with " + "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n", + resource, pResource -> pending, pResource -> split, pResource -> unpack, + (void *) pResource -> drawable, (void *) pResource -> region, + pResource -> commit, (void *) pResource -> gc); + } + + pResource -> pending = 1; + pResource -> split = resource; + + return pResource; +} + +void nxagentFreeSplitResource(SplitResourcePtr pResource) +{ + if (pResource -> pending == 0 || pResource -> split == NXNoResource || + pResource -> drawable != NULL || pResource -> region != NullRegion || + pResource -> gc != NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentFreeSplitResource: PANIC! Invalid record provided with values " + "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n", + pResource -> pending, pResource -> split, pResource -> unpack, + (void *) pResource -> drawable, (void *) pResource -> region, + pResource -> commit, (void *) pResource -> gc); + #endif + + FatalError("nxagentFreeSplitResource: PANIC! Invalid record provided with values " + "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n", + pResource -> pending, pResource -> split, pResource -> unpack, + (void *) pResource -> drawable, (void *) pResource -> region, + pResource -> commit, (void *) pResource -> gc); + } + + #ifdef TEST + fprintf(stderr, "nxagentFreeSplitResource: Clearing the record for resource [%d].\n", + pResource -> split); + #endif + + NXFreeSplit(nxagentDisplay, pResource -> split); + + pResource -> pending = 0; + pResource -> commit = 0; + pResource -> split = NXNoResource; + pResource -> unpack = NXNoResource; + pResource -> drawable = NULL; + pResource -> region = NullRegion; + pResource -> gc = NULL; +} + +void nxagentInitUnpackResources() +{ +/* +FIXME: This must be implemented. +*/ +} + +UnpackResourcePtr nxagentAllocUnpackResource() +{ +/* +FIXME: This must be implemented. +*/ + return NULL; +} + +void nxagentFreeUnpackResource(UnpackResourcePtr pResource) +{ +/* +FIXME: This must be implemented. +*/ +} + +void nxagentReleaseAllSplits(void) +{ + int resource; + + #ifdef TEST + fprintf(stderr, "nxagentReleaseAllSplits: Going to release all the split resources.\n"); + #endif + + for (resource = 0; resource < NXNumberOfResources; resource++) + { + SplitResourcePtr pResource = &nxagentSplitResources[resource]; + + if (pResource != NULL && pResource -> pending == 1) + { + DrawablePtr pDrawable = pResource -> drawable; + + if (pDrawable != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentReleaseAllSplits: Releasing the drawable at [%p] for " + "resource [%d].\n", (void *) pDrawable, pResource -> split); + #endif + + nxagentReleaseSplit(pDrawable); + } + + #ifdef TEST + fprintf(stderr, "nxagentReleaseAllSplits: Freeing the resource [%d].\n", + resource); + #endif + + nxagentFreeSplitResource(pResource); + } + } +} + +/* + * Check the coherency of the split record. + */ + +#ifdef TEST + +static void nxagentCheckSplit(DrawablePtr pDrawable, SplitResourcePtr pResource) +{ + if (pResource == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentCheckSplit: PANIC! No record associated to drawable at [%p].\n", + (void *) pDrawable); + #endif + + FatalError("nxagentCheckSplit: PANIC! No record associated to drawable at [%p].\n", + (void *) pDrawable); + } + else if (pResource -> drawable != pDrawable || + pResource -> split == NXNoResource) + { + #ifdef PANIC + fprintf(stderr, "nxagentCheckSplit: PANIC! The record [%d] doesn't match the drawable at [%p].\n", + pResource -> split, (void *) pDrawable); + #endif + + FatalError("nxagentCheckSplit: PANIC! The record [%d] doesn't match the drawable at [%p].\n", + pResource -> split, (void *) pDrawable); + } + else if (pResource -> commit == 1 && + pResource -> gc == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentCheckSplit: PANIC! The record [%d] doesn't have a valid GC.\n", + pResource -> split); + #endif + + FatalError("nxagentCheckSplit: PANIC! The record [%d] doesn't have a valid GC.\n", + pResource -> split); + } +} + +static void nxagentCheckResource(SplitResourcePtr pResource, int resource) +{ + if (pResource == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentCheckResource: PANIC! No record associated to resource [%d].\n", + resource); + #endif + + FatalError("nxagentCheckResource: PANIC! No record associated to resource [%d].\n", + resource); + } + else if ((pResource -> split != resource || pResource -> pending != 1) || + (pResource -> commit == 1 && (pResource -> drawable == NULL || + pResource -> gc == NULL))) + { + #ifdef PANIC + fprintf(stderr, "nxagentCheckResource: PANIC! Invalid record for resource [%d] with " + "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n", + resource, pResource -> pending, pResource -> split, pResource -> unpack, + (void *) pResource -> drawable, (void *) pResource -> region, + pResource -> commit, (void *) pResource -> gc); + #endif + + FatalError("nxagentCheckResource: PANIC! Invalid record for resource [%d] with " + "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n", + resource, pResource -> pending, pResource -> split, pResource -> unpack, + (void *) pResource -> drawable, (void *) pResource -> region, + pResource -> commit, (void *) pResource -> gc); + } +} + +#endif + +int nxagentCreateSplit(DrawablePtr pDrawable, GCPtr *pGC) +{ + SplitResourcePtr pResource; + + pDrawable = nxagentSplitDrawable(pDrawable); + + pResource = nxagentAllocSplitResource(); + + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentPixmapPriv((PixmapPtr) pDrawable) -> splitResource = pResource; + } + else + { + nxagentWindowPriv((WindowPtr) pDrawable) -> splitResource = pResource; + } + + pResource -> drawable = pDrawable; + pResource -> commit = 1; + + /* + * Make a copy of the GC so the client + * can safely remove it. + */ + + pResource -> gc = CreateScratchGC(pDrawable -> pScreen, pDrawable -> depth); + +/* +FIXME: What do we do here? +*/ + if (pResource -> gc == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentCreateSplit: PANIC! Failed to create split GC for resource [%d].\n", + pResource -> split); + #endif + + FatalError("nxagentCreateSplit: PANIC! Failed to create split GC for resource [%d].\n", + pResource -> split); + } + else if (CopyGC(*pGC, pResource -> gc, GCFunction | GCPlaneMask | + GCSubwindowMode | GCClipXOrigin | GCClipYOrigin | + GCClipMask | GCForeground | GCBackground) != Success) + { +/* +FIXME: What do we do here? +*/ + #ifdef PANIC + fprintf(stderr, "nxagentCreateSplit: PANIC! Failed to copy split GC for resource [%d].\n", + pResource -> split); + #endif + + FatalError("nxagentCreateSplit: PANIC! Failed to copy split GC for resource [%d].\n", + pResource -> split); + } + + #ifdef TEST + fprintf(stderr, "nxagentCreateSplit: Associated GC at [%p] to resource [%d] " + "with id [%lu].\n", (void *) pResource -> gc, pResource -> split, + (unsigned long) nxagentGC(pResource -> gc)); + #endif + + *pGC = pResource -> gc; + + #ifdef TEST + fprintf(stderr, "nxagentCreateSplit: Associated resource [%d] to drawable at [%p].\n", + pResource -> split, (void *) pResource -> drawable); + #endif + + return pResource -> split; +} + +/* + * Set the region to be the current + * streaming region. + */ + +void nxagentRegionSplit(DrawablePtr pDrawable, RegionPtr pRegion) +{ + SplitResourcePtr pResource; + + pDrawable = nxagentSplitDrawable(pDrawable); + + pResource = nxagentSplitResource(pDrawable); + + #ifdef TEST + + fprintf(stderr, "nxagentRegionSplit: Associating region to resource [%d] drawable at [%p].\n", + pResource -> split, (void *) pDrawable); + + nxagentCheckSplit(pDrawable, pResource); + + #endif + + if (pResource == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentRegionSplit: PANIC! No valid split record for drawable at [%p].\n", + (void *) pDrawable); + #endif + + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentRegionSplit: Associated region [%d,%d,%d,%d] to drawable at [%p] " + "with resource [%d].\n", pRegion -> extents.x1, pRegion -> extents.y1, + pRegion -> extents.x2, pRegion -> extents.y2, (void *) pDrawable, + pResource -> split); + #endif + + pResource -> region = pRegion; +} + +/* + * Remove the association between the drawable + * and the split resource. The resource is not + * deallocated until the end of the split. + */ + +void nxagentReleaseSplit(DrawablePtr pDrawable) +{ + SplitResourcePtr pResource; + + pDrawable = nxagentSplitDrawable(pDrawable); + + pResource = nxagentSplitResource(pDrawable); + + if (pResource == NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentReleaseSplit: No split resources for drawable at [%p].\n", + (void *) pDrawable); + #endif + + return; + } + + #ifdef TEST + + fprintf(stderr, "nxagentReleaseSplit: Going to release resource [%d] for drawable at [%p].\n", + pResource -> split, (void *) pDrawable); + + nxagentCheckSplit(pDrawable, pResource); + + #endif + + if (pResource -> region != NullRegion) + { + /* + * If we have a region the commits + * had to be still valid. In this + * case tell the proxy to abort the + * data transfer. + */ + + #ifdef TEST + + if (pResource -> commit == 0) + { + #ifdef PANIC + fprintf(stderr, "nxagentReleaseSplit: PANIC! Found a region for resource [%d] but the " + "commits are invalid.\n", pResource -> split); + #endif + + FatalError("nxagentCheckSplit: PANIC! Found a region for resource [%d] but the " + "commits are invalid.\n", pResource -> split); + } + + #endif + + #ifdef TEST + fprintf(stderr, "nxagentValidateSplit: Aborting the data transfer for resource [%d].\n", + pResource -> split); + #endif + + NXAbortSplit(nxagentDisplay, pResource -> split); + + #ifdef TEST + fprintf(stderr, "nxagentReleaseSplit: Freeing the region for drawable at [%p].\n", + (void *) pDrawable); + #endif + + RegionDestroy(pResource -> region); + + pResource -> region = NullRegion; + } + + if (pResource -> gc != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentReleaseSplit: Freeing the split GC for drawable at [%p].\n", + (void *) pDrawable); + #endif + + FreeScratchGC(pResource -> gc); + + pResource -> gc = NULL; + } + + /* + * Remove the association between the + * drawable and the resource record. + */ + + #ifdef TEST + fprintf(stderr, "nxagentReleaseSplit: Removing association to drawable at [%p].\n", + (void *) pDrawable); + #endif + + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + nxagentPixmapPriv((PixmapPtr) pDrawable) -> splitResource = NULL; + } + else + { + nxagentWindowPriv((WindowPtr) pDrawable) -> splitResource = NULL; + } + + /* + * Invalidate the commits and remove the + * association between the resource and + * the drawable. + */ + + pResource -> drawable = NULL; + pResource -> commit = 0; +} + +void nxagentValidateSplit(DrawablePtr pDrawable, RegionPtr pRegion) +{ + SplitResourcePtr pResource; + + pDrawable = nxagentSplitDrawable(pDrawable); + + pResource = nxagentSplitResource(pDrawable); + + if (pResource == NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentValidateSplit: No split resource for drawable at [%p].\n", + (void *) pDrawable); + #endif + + return; + } + else if (pResource -> region == NullRegion) + { + #ifdef TEST + fprintf(stderr, "nxagentValidateSplit: No split region yet for drawable at [%p].\n", + (void *) pDrawable); + #endif + + return; + } + else if (pResource -> commit == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentValidateSplit: WARNING! Split for drawable at [%p] was " + "already invalidated.\n", (void *) pDrawable); + #endif + + return; + } + + #ifdef TEST + + fprintf(stderr, "nxagentValidateSplit: Going to validate resource [%d] drawable at [%p].\n", + pResource -> split, (void *) pDrawable); + + nxagentCheckSplit(pDrawable, pResource); + + #endif + + #ifdef TEST + fprintf(stderr, "nxagentValidateSplit: Checking the region for resource [%d] " + "and drawable at [%p].\n", pResource -> split, (void *) pDrawable); + #endif + + /* + * If a null region is passed as parameter, + * we assume that all the commits have to + * be discarded. + */ + + if (pRegion == NullRegion) + { + #ifdef TEST + fprintf(stderr, "nxagentValidateSplit: Forcing all commits as invalid for " + "drawable at [%p].\n", (void *) pDrawable); + #endif + + nxagentReleaseSplit(pDrawable); + } + else + { + RegionRec tmpRegion; + + /* + * Check if the provided region overlaps + * the area covered by the image being + * streamed. + */ + + RegionInit(&tmpRegion, NullBox, 1); + + RegionIntersect(&tmpRegion, pResource -> region, pRegion); + + if (RegionNil(&tmpRegion) == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentValidateSplit: Marking the overlapping commits as invalid " + "for drawable at [%p].\n", (void *) pDrawable); + #endif + + nxagentReleaseSplit(pDrawable); + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentValidateSplit: Leaving the commits as valid for " + "drawable at [%p].\n", (void *) pDrawable); + } + #endif + + RegionUninit(&tmpRegion); + } +} + +void nxagentFreeSplit(int resource) +{ + DrawablePtr pDrawable; + + SplitResourcePtr pResource = &nxagentSplitResources[resource]; + + if (pResource == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentFreeSplit: PANIC! No valid split record for resource [%d].\n", + resource); + #endif + + FatalError("nxagentFreeSplit: PANIC! No valid split record for resource [%d].\n", + resource); + } + else if (pResource -> split != resource) + { + #ifdef PANIC + fprintf(stderr, "nxagentFreeSplit: PANIC! The record [%d] doesn't match the resource [%d].\n", + pResource -> split, resource); + #endif + + FatalError("nxagentFreeSplit: PANIC! The record [%d] doesn't match the resource [%d].\n", + pResource -> split, resource); + } + + pDrawable = pResource -> drawable; + + if (pDrawable != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentFreeSplit: Removing association to drawable at [%p].\n", + (void *) pDrawable); + #endif + + nxagentReleaseSplit(pDrawable); + } + #ifdef TEST + else + { + /* + * The end of the split has come after we have + * invalidated the operation and removed the + * association to the drawable. This happens, + * for example, if the drawable is destroyed. + */ + + fprintf(stderr, "nxagentFreeSplit: WARNING! Releasing invalidated resource [%d].\n", + pResource -> split); + } + #endif + + #ifdef TEST + fprintf(stderr, "nxagentFreeSplit: Freeing the record for resource [%d].\n", + pResource -> split); + #endif + + nxagentFreeSplitResource(pResource); +} + +/* +FIXME: This must be enabled when the vanilla + synchronization procedure is working. +*/ +#define USE_FINISH_SPLIT + +void nxagentWaitDrawable(DrawablePtr pDrawable) +{ + SplitResourcePtr pResource; + + pDrawable = nxagentSplitDrawable(pDrawable); + + pResource = nxagentSplitResource(pDrawable); + + if (pResource == NULL) + { + #ifdef TEST + fprintf(stderr, "++++++nxagentWaitDrawable: WARNING! The drawable at [%p] is already awake.\n", + (void *) pDrawable); + #endif + + return; + } + + #ifdef TEST + fprintf(stderr, "++++++nxagentWaitDrawable: Waiting drawable at [%p] with resource [%d].\n", + (void *) pDrawable, pResource -> split); + #endif + + /* + * Be sure we intercept an I/O error + * as well as an interrupt. + */ + + #ifdef USE_FINISH_SPLIT + + NXFinishSplit(nxagentDisplay, pResource -> split); + + #endif + + NXFlushDisplay(nxagentDisplay, NXFlushBuffer); + + for (;;) + { + /* + * Handling all the possible events here + * preempts the queue and makes a better + * use of the link. + * + * We should better use XIfEvent() instead + * of looping again and again through the + * event queue. + */ + + nxagentDispatchEvents(NULL); + + /* + * Wait indefinitely until the resource + * is released or the display is shut + * down. + */ + + if (nxagentSplitResource(pDrawable) == NULL || + NXDisplayError(nxagentDisplay) == 1) + { + #ifdef TEST + + if (NXDisplayError(nxagentDisplay) == 1) + { + fprintf(stderr, "++++++nxagentWaitDrawable: WARNING! Display error detected while " + "waiting for the drawable.\n"); + } + else + { + fprintf(stderr, "++++++nxagentWaitDrawable: Drawable at [%p] can now be restarted.\n", + (void *) pDrawable); + } + + #endif + + return; + } + + #ifdef TEST + fprintf(stderr, "++++++nxagentWaitDrawable: Yielding control to the NX transport.\n"); + #endif + + nxagentWaitEvents(nxagentDisplay, NULL); + } +} + +static Bool nxagentCommitSplitPredicate(Display *display, XEvent *event, XPointer ptr) +{ + return (event -> type == ClientMessage && + event -> xclient.data.l[0] == NXCommitSplitNotify && + event -> xclient.window == 0 && event -> xclient.message_type == 0 && + event -> xclient.format == 32); +} + +void nxagentWaitCommitEvent(int resource) +{ + XEvent event; + + /* + * Check if there is any commit pending. As + * we are at it, handle any commit, even those + * commits pertaining to other resources. + * + * We can receive some commits even if we'll + * later receive a no-split event. The proxy, + * in fact, may have missed to find the image + * in the memory cache and could have loaded it + * from disk (so requiring a commit) before we + * marked the end of the split sequence. + */ + + while (nxagentCheckEvents(nxagentDisplay, &event, + nxagentCommitSplitPredicate, NULL) == 1) + { + int client = event.xclient.data.l[1]; + int request = event.xclient.data.l[2]; + int position = event.xclient.data.l[3]; + + #ifdef TEST + fprintf(stderr, "nxagentWaitCommitEvent: Commit event received with " + "client [%d] request [%d] and position [%d].\n", + client, request, position); + #endif + + nxagentHandleCommitSplitEvent(client, request, position); + } +} + +static Bool nxagentWaitSplitPredicate(Display *display, XEvent *event, XPointer ptr) +{ + return (event -> type == ClientMessage && + (event -> xclient.data.l[0] == NXNoSplitNotify || + event -> xclient.data.l[0] == NXStartSplitNotify) && + event -> xclient.window == 0 && event -> xclient.message_type == 0 && + event -> xclient.format == 32); +} + +int nxagentWaitSplitEvent(int resource) +{ + XEvent event; + + int split = 0; + + /* + * Don't flush the link. We only want to + * query the NX transport to check whether + * the operation caused a split. + */ + + NXFlushDisplay(nxagentDisplay, NXFlushBuffer); + + for (;;) + { + #ifdef TEST + fprintf(stderr, "nxagentWaitSplitEvent: Waiting for the split event for resource [%d].\n", + resource); + #endif + + XIfEvent(nxagentDisplay, &event, nxagentWaitSplitPredicate, NULL); + + if (NXDisplayError(nxagentDisplay) == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentWaitSplitEvent: WARNING! Error detected reading the event.\n"); + #endif + + nxagentHandleNoSplitEvent(resource); + + break; + } + + #ifdef TEST + fprintf(stderr, "nxagentWaitSplitEvent: Going to process the split event.\n"); + #endif + + if (resource != (int) event.xclient.data.l[1]) + { + #ifdef PANIC + fprintf(stderr, "nxagentWaitSplitEvent: PANIC! Got event for resource [%d] while " + "waiting for resource [%d].\n", (int) event.xclient.data.l[1], resource); + + fprintf(stderr, "nxagentWaitSplitEvent: PANIC! Restarting resource [%d] due to the " + "missing split event.\n", resource); + #endif + + nxagentHandleNoSplitEvent(resource); + + break; + } + else if (event.xclient.data.l[0] == NXNoSplitNotify) + { + nxagentHandleNoSplitEvent(resource); + + break; + } + else + { + nxagentHandleStartSplitEvent(resource); + + split = 1; + + break; + } + } + + return split; +} + +void nxagentHandleNoSplitEvent(int resource) +{ + if (resource >= 0 && resource < NXNumberOfResources) + { + #ifdef TEST + + SplitResourcePtr pResource = &nxagentSplitResources[resource]; + + fprintf(stderr, "nxagentHandleNoSplitEvent: Received event for resource [%d].\n", + resource); + + nxagentCheckResource(pResource, resource); + + #endif + + #ifdef TEST + fprintf(stderr, "nxagentHandleNoSplitEvent: Checking if there is any commit pending.\n"); + #endif + + nxagentWaitCommitEvent(resource); + + #ifdef TEST + fprintf(stderr, "nxagentHandleNoSplitEvent: No streaming was required with resource [%d] " + "and drawable at [%p].\n", resource, (void *) pResource -> drawable); + #endif + + /* + * Release the resource. + */ + + nxagentFreeSplit(resource); + } + #ifdef PANIC + else + { + fprintf(stderr, "nxagentHandleNoSplitEvent: PANIC! Invalid resource identifier [%d] " + " received in event.\n", resource); + } + #endif +} + +void nxagentHandleStartSplitEvent(int resource) +{ + if (resource >= 0 && resource < NXNumberOfResources) + { + #ifdef TEST + + SplitResourcePtr pResource = &nxagentSplitResources[resource]; + + fprintf(stderr, "nxagentHandleStartSplitEvent: Received event for resource [%d].\n", + resource); + + nxagentCheckResource(pResource, resource); + + #endif + + #ifdef TEST + fprintf(stderr, "nxagentHandleStartSplitEvent: Checking if there is any commit pending.\n"); + #endif + + nxagentWaitCommitEvent(resource); + + #ifdef TEST + fprintf(stderr, "nxagentHandleStartSplitEvent: Streaming started with resource [%d] " + "and drawable at [%p].\n", resource, (void *) pResource -> drawable); + #endif + } + #ifdef PANIC + else + { + fprintf(stderr, "nxagentHandleStartSplitEvent: PANIC! Invalid resource identifier [%d] " + " received in event.\n", resource); + } + #endif +} + +void nxagentHandleCommitSplitEvent(int resource, int request, int position) +{ + if (resource >= 0 && resource < NXNumberOfResources && + request >= 0 && position >= 0) + { + SplitResourcePtr pResource = &nxagentSplitResources[resource]; + + #ifdef TEST + fprintf(stderr, "nxagentHandleCommitSplitEvent: Received event for resource [%d].\n", + resource); + #endif + + if (pResource != NULL && pResource -> commit == 1) + { + #ifdef TEST + + nxagentCheckResource(pResource, resource); + + fprintf(stderr, "nxagentHandleCommitSplitEvent: Committing request [%d] with " + "position [%d] for resource [%d].\n", request, position, resource); + + #endif + + NXCommitSplit(nxagentDisplay, resource, 1, request, position); + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentHandleCommitSplitEvent: Discarding request [%d] for " + "resource [%d] with position [%d].\n", request, resource, position); + #endif + + NXCommitSplit(nxagentDisplay, resource, 0, request, position); + } + } + #ifdef PANIC + else + { + fprintf(stderr, "nxagentHandleCommitSplitEvent: PANIC! Invalid commit event with " + "request [%d] and position [%d] for resource [%d].\n", request, + position, resource); + } + #endif +} + +void nxagentHandleEndSplitEvent(int resource) +{ + if (resource >= 0 && resource < NXNumberOfResources) + { + SplitResourcePtr pResource = &nxagentSplitResources[resource]; + + #ifdef TEST + fprintf(stderr, "nxagentHandleEndSplitEvent: Received event for resource [%d].\n", + resource); + + nxagentCheckResource(pResource, resource); + + #endif + + #ifdef TEST + fprintf(stderr, "nxagentHandleEndSplitEvent: Checking if there is any commit pending.\n"); + #endif + + nxagentWaitCommitEvent(resource); + + if (pResource != NULL && pResource -> commit == 1) + { + #ifdef TEST + + fprintf(stderr, "nxagentHandleEndSplitEvent: Checking the split region at [%p] " + "for drawable at [%p].\n", (void *) pResource -> drawable, + (void *) pResource -> region); + + if (pResource -> region == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentHandleEndSplitEvent: PANIC! Invalid region [%p] for drawable at [%p].\n", + (void *) pResource -> region, (void *) pResource -> drawable); + #endif + + FatalError("nxagentHandleEndSplitEvent: PANIC! Invalid region [%p] for drawable at [%p].\n", + (void *) pResource -> region, (void *) pResource -> drawable); + } + else if (pResource -> gc == NULL) + { + #ifdef PANIC + fprintf(stderr, "nxagentHandleEndSplitEvent: PANIC! Invalid GC [%p] for drawable at [%p].\n", + (void *) pResource -> gc, (void *) pResource -> drawable); + #endif + + FatalError("nxagentHandleEndSplitEvent: PANIC! Invalid GC [%p] for drawable at [%p].\n", + (void *) pResource -> gc, (void *) pResource -> drawable); + } + + #endif + + if (pResource -> drawable != NULL && + pResource -> region != NullRegion) + { + if (RegionNil(pResource -> region) == 0) + { + RegionSubtract( + nxagentCorruptedRegion(pResource -> drawable), + nxagentCorruptedRegion(pResource -> drawable), + pResource -> region); + +/* +FIXME: Implementing the valid region policy + + nxagentExpandValidRegion(pResource -> drawable, pResource -> region); +*/ + + #ifdef TEST + fprintf(stderr, "nxagentHandleEndSplitEvent: Synchronized region [%d,%d,%d,%d] " + "for drawable at [%p].\n", pResource -> region -> extents.x1, + pResource -> region -> extents.y1, pResource -> region -> extents.x2, + pResource -> region -> extents.y2, (void *) pResource -> drawable); + #endif + } + else + { + #ifdef PANIC + fprintf(stderr, "nxagentHandleEndSplitEvent: PANIC! The region [%d,%d,%d,%d] for drawable " + "at [%p] is empty.\n", pResource -> region -> extents.x1, + pResource -> region -> extents.y1, pResource -> region -> extents.x2, + pResource -> region -> extents.y2, (void *) pResource -> drawable); + #endif + + FatalError("nxagentHandleEndSplitEvent: PANIC! The region [%d,%d,%d,%d] for drawable " + "at [%p] is empty.\n", pResource -> region -> extents.x1, + pResource -> region -> extents.y1, pResource -> region -> extents.x2, + pResource -> region -> extents.y2, (void *) pResource -> drawable); + } + } + else + { + #ifdef PANIC + fprintf(stderr, "nxagentHandleEndSplitEvent: PANIC! Invalid record for resource [%d] with " + "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n", + resource, pResource -> pending, pResource -> split, pResource -> unpack, + (void *) pResource -> drawable, (void *) pResource -> region, + pResource -> commit, (void *) pResource -> gc); + #endif + + FatalError("nxagentHandleEndSplitEvent: PANIC! Invalid record for resource [%d] with " + "pending [%d] split [%d] unpack [%d] drawable [%p] region [%p] commit [%d] gc [%p].\n", + resource, pResource -> pending, pResource -> split, pResource -> unpack, + (void *) pResource -> drawable, (void *) pResource -> region, + pResource -> commit, (void *) pResource -> gc); + } + } + + /* + * Release the resource. + */ + + nxagentFreeSplit(resource); + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentHandleEndSplitEvent: WARNING! Ignoring split event " + "for resource [%d].\n", resource); + } + #endif +} + +void nxagentHandleEmptySplitEvent() +{ +/* +FIXME: Should run a consistency check here. +*/ + #ifdef TEST + fprintf(stderr, "nxagentHandleEmptySplitEvent: No more split event to handle.\n"); + #endif +} + +/* + * The drawable is going to become corrupted. + */ + +void nxagentSetCorruptedTimestamp(DrawablePtr pDrawable) +{ + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "nxagentSetCorruptedTimestamp: Corruption timestamp for pixmap at [%p] was [%lu].\n", + (void *) pDrawable, nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp); + #endif + + nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp = GetTimeInMillis(); + + #ifdef TEST + fprintf(stderr, "nxagentSetCorruptedTimestamp: New corruption timestamp for pixmap at [%p] is [%lu].\n", + (void *) pDrawable, nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp); + #endif + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentSetCorruptedTimestamp: Corruption timestamp for window at [%p] was [%lu].\n", + (void *) pDrawable, nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp); + #endif + + nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp = GetTimeInMillis(); + + #ifdef TEST + fprintf(stderr, "nxagentSetCorruptedTimestamp: New corruption timestamp for window at [%p] is [%lu].\n", + (void *) pDrawable, nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp); + #endif + } + } +} + +/* + * Reset the timestamp taken when the drawable + * became initially corrupted. The timestamp is + * reset only after the drawable has been fully + * synchronized. + */ + +void nxagentResetCorruptedTimestamp(DrawablePtr pDrawable) +{ + if (nxagentDrawableStatus(pDrawable) == Synchronized) + { + if (pDrawable -> type == DRAWABLE_PIXMAP) + { + #ifdef TEST + fprintf(stderr, "nxagentResetCorruptedTimestamp: Corruption timestamp for pixmap at [%p] was [%lu].\n", + (void *) pDrawable, nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp); + #endif + + nxagentPixmapPriv((PixmapPtr) pDrawable) -> corruptedTimestamp = 0; + } + else + { + #ifdef TEST + fprintf(stderr, "nxagentResetCorruptedTimestamp: Corruption timestamp for window at [%p] was [%lu].\n", + (void *) pDrawable, nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp); + #endif + + nxagentWindowPriv((WindowPtr) pDrawable) -> corruptedTimestamp = 0; + } + } +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Split.h b/nx-X11/programs/Xserver/hw/nxagent/Split.h new file mode 100644 index 000000000..65db133bd --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Split.h @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Split_H__ +#define __Split_H__ + +typedef struct _SplitResourceRec +{ + int pending; + int split; + int unpack; + DrawablePtr drawable; + RegionPtr region; + GCPtr gc; + int commit; + +} SplitResourceRec; + +typedef SplitResourceRec *SplitResourcePtr; + +extern SplitResourceRec nxagentSplitResources[]; + +typedef struct _UnpackResourceRec +{ + int pending; + int unpack; + DrawablePtr drawable; + +} UnpackResourceRec; + +typedef UnpackResourceRec *UnpackResourcePtr; + +extern UnpackResourceRec nxagentUnpackResources[]; + +void nxagentInitSplitResources(); +void nxagentInitUnpackResources(); + +SplitResourcePtr nxagentAllocSplitResource(); +void nxagentFreeSplitResource(SplitResourcePtr pResource); + +UnpackResourcePtr nxagentAllocUnpackResource(); +void nxagentFreeUnpackResource(UnpackResourcePtr pResource); + +#define nxagentSplitResource(pDrawable) \ + ((pDrawable) -> type == DRAWABLE_PIXMAP ? \ + (nxagentPixmapPriv(nxagentRealPixmap((PixmapPtr) pDrawable)) -> splitResource) : \ + (nxagentWindowPriv((WindowPtr) pDrawable) -> splitResource)) + +/* +FIXME: Make it a real function to log a warning + in the logs. + +#define nxagentSplitDrawable(pDrawable) \ + (((pDrawable) -> type == DRAWABLE_PIXMAP && \ + nxagentPixmapIsVirtual((PixmapPtr) pDrawable)) ? \ + (DrawablePtr) nxagentRealPixmap((PixmapPtr) pDrawable) : pDrawable) +*/ +DrawablePtr nxagentSplitDrawable(DrawablePtr pDrawable); + +int nxagentCreateSplit(DrawablePtr pDrawable, GCPtr *pGC); +void nxagentRegionSplit(DrawablePtr pDrawable, RegionPtr pRegion); +void nxagentValidateSplit(DrawablePtr pDrawable, RegionPtr pRegion); +void nxagentReleaseSplit(DrawablePtr pDrawable); + +void nxagentReleaseAllSplits(void); + +void nxagentSetCorruptedTimestamp(DrawablePtr pDrawable); +void nxagentResetCorruptedTimestamp(DrawablePtr pDrawable); + +#endif /* __Split_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/TestExt.c b/nx-X11/programs/Xserver/hw/nxagent/TestExt.c new file mode 100644 index 000000000..51a2ecb3d --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/TestExt.c @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include <nx-X11/X.h> +#include <nx-X11/Xproto.h> +#include <nx-X11/Xlib.h> +#undef Bool +#include "screenint.h" +#include "input.h" +#include "misc.h" +#include "scrnintstr.h" +#include "servermd.h" +#include "mipointer.h" +#define XTestSERVER_SIDE +#include "xtestext1.h" + +extern CARD32 nxagentLastEventTime; + +void XTestGetPointerPos(short *fmousex, short *fmousey); + +void XTestJumpPointer(int jx, int jy, int dev_type); + +void XTestGenerateEvent(int dev_type, int keycode, int keystate, + int mousex, int mousey); + +void XTestGetPointerPos(short *fmousex, short *fmousey) +{ + int x,y; + + miPointerPosition(&x, &y); + *fmousex = x; + *fmousey = y; +} + +void XTestJumpPointer(int jx, int jy, int dev_type) +{ + miPointerAbsoluteCursor(jx, jy, GetTimeInMillis()); +} + +void XTestGenerateEvent(int dev_type, int keycode, int keystate, + int mousex, int mousey) +{ +/* + xEvent tevent; + + tevent.u.u.type = (dev_type == XE_POINTER) ? + (keystate == XTestKEY_UP) ? ButtonRelease : ButtonPress : + (keystate == XTestKEY_UP) ? KeyRelease : KeyPress; + tevent.u.u.detail = keycode; + tevent.u.keyButtonPointer.rootX = mousex; + tevent.u.keyButtonPointer.rootY = mousey; + tevent.u.keyButtonPointer.time = nxagentLastEventTime = GetTimeInMillis(); + mieqEnqueue(&tevent); +*/ +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Trap.c b/nx-X11/programs/Xserver/hw/nxagent/Trap.c new file mode 100644 index 000000000..c582f6a16 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Trap.c @@ -0,0 +1,122 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include "Trap.h" + +/* + * Set if we are dispatching a render + * extension request. Used to avoid + * reentrancy in GC operations. + */ + +int nxagentGCTrap = 0; + +/* + * Set if we are enqueing an internal + * operation, CreateWindow and Reparent- + * Window. Used to remove any screen operation. + */ + +int nxagentScreenTrap = 0; + +/* + * Set if we detected that our RENDER + * implementation is faulty. + */ + +int nxagentRenderTrap = 0; + +/* + * Set if we are executing a GC operation + * only on the X side. Used to avoid + * reentrancy in FB layer. + */ + +int nxagentFBTrap = 0; + +/* + * Set if we are dispatching a shared + * memory extension request. + */ + +int nxagentShmTrap = 0; + +/* + * Set if a shared pixmap operation is + * requested by the client. + */ + +int nxagentShmPixmapTrap = 0; + +/* + * Set if we are dispatching a XVideo + * extension request. + */ + +int nxagentXvTrap = 0; + +/* + * Set if we are dispatching a GLX + * extension request. + */ + +int nxagentGlxTrap = 0; + +/* + * Set while we are resuming the session. + */ + +int nxagentReconnectTrap = 0; + +/* + * Set if we need to realize a drawable + * by using a lossless encoding. + */ + +int nxagentLosslessTrap = 0; + +/* + * Set to force the synchronization of + * a drawable. + */ + +int nxagentSplitTrap = 0; + +/* + * Set to avoid CapsLock synchronization + * problems when CapsLock is the first + * key to be pressed in the session. + */ + +int nxagentXkbCapsTrap = 0; + +/* + * Set to avoid NumLock synchronization + * problems when NumLock is the first + * key to be pressed in the session. + */ + +int nxagentXkbNumTrap = 0; + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Trap.h b/nx-X11/programs/Xserver/hw/nxagent/Trap.h new file mode 100644 index 000000000..f0884f657 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Trap.h @@ -0,0 +1,124 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Traps_H__ +#define __Traps_H__ + +/* + * Set if we are dispatching a render + * extension request. Used to avoid + * reentrancy in GC operations. + */ + +extern int nxagentGCTrap; + +/* + * Set if we are enqueing an internal + * operation, CreateWindow and Reparent- + * Window. Used to remove any screen operation. + */ + +extern int nxagentScreenTrap; + +/* + * Set if we detected that our RENDER + * implementation is faulty. + */ + +extern int nxagentRenderTrap; + +/* + * Set if we are executing a GC operation + * only on the X side. Used to avoid + * reentrancy in FB layer. + */ + +extern int nxagentFBTrap; + +/* + * Set if we are dispatching a shared + * memory extension request. + */ + +extern int nxagentShmTrap; + +/* + * Set if a shared pixmap operation is + * requested by the client. + */ + +extern int nxagentShmPixmapTrap; + +/* + * Set if we are dispatching a XVideo + * extension request. + */ + +extern int nxagentXvTrap; + +/* + * Set if we are dispatching a GLX + * extension request. + */ + +extern int nxagentGlxTrap; + +/* + * Set while we are resuming the session. + */ + +extern int nxagentReconnectTrap; + +/* + * Set if we need to realize a drawable + * by using a lossless encoding. + */ + +extern int nxagentLosslessTrap; + +/* + * Set to force the synchronization of + * a drawable. + */ + +extern int nxagentSplitTrap; + +/* + * Set to avoid CapsLock synchronization + * problems when CapsLock is the first + * key to be pressed in the session. + */ + +extern int nxagentXkbCapsTrap; + +/* + * Set to avoid NumLock synchronization + * problems when NumLock is the first + * key to be pressed in the session. + */ + +extern int nxagentXkbNumTrap; + +#endif /* __Trap_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Utils.h b/nx-X11/programs/Xserver/hw/nxagent/Utils.h new file mode 100644 index 000000000..8a3335424 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Utils.h @@ -0,0 +1,55 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Utils_H__ +#define __Utils_H__ + +/* + * Number of bits in fixed point operations. + */ + +#define PRECISION 16 + +/* + * "1" ratio means "don't scale". + */ + +#define DONT_SCALE (1 << PRECISION) + +#define nxagentScale(i, ratio) (((i) * (ratio)) >> (PRECISION)) + +#ifndef MIN +#define MIN(A, B) ( (A) < (B) ? (A) : (B) ) +#endif + +#ifndef MAX +#define MAX(A, B) ( (A) > (B) ? (A) : (B) ); +#endif + +static inline const char * validateString(const char *str) { + return str ? str : "(null)"; +} + +#endif /* __Utils_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Visual.c b/nx-X11/programs/Xserver/hw/nxagent/Visual.c new file mode 100644 index 000000000..eebd1fcc1 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Visual.c @@ -0,0 +1,167 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#include "scrnintstr.h" +#include "dix.h" +#include "mi.h" +#include "mibstore.h" +#include "resource.h" + +#include "X.h" +#include "Xproto.h" + +#include "Agent.h" +#include "Display.h" +#include "Visual.h" + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Predefined visual used for drawables + * having a 32 bits depth. + */ + +Visual nxagentAlphaVisual; + +Visual *nxagentVisual(VisualPtr pVisual) +{ + XVisualInfo visual; + + int i; + + visual.class = pVisual->class; + visual.bits_per_rgb = pVisual->bitsPerRGBValue; + visual.colormap_size = pVisual->ColormapEntries; + visual.depth = pVisual->nplanes; + visual.red_mask = pVisual->redMask; + visual.green_mask = pVisual->greenMask; + visual.blue_mask = pVisual->blueMask; + + for (i = 0; i < nxagentNumVisuals; i++) + { + if (nxagentCompareVisuals(visual, nxagentVisuals[i]) == 1) + { + return nxagentVisuals[i].visual; + } + } + + return NULL; +} + +Visual *nxagentVisualFromID(ScreenPtr pScreen, VisualID visual) +{ + int i; + + for (i = 0; i < pScreen->numVisuals; i++) + { + if (pScreen->visuals[i].vid == visual) + { + return nxagentVisual(&pScreen->visuals[i]); + } + } + + return NULL; +} + +Colormap nxagentDefaultVisualColormap(Visual *visual) +{ + int i; + + for (i = 0; i < nxagentNumVisuals; i++) + { + if (nxagentVisuals[i].visual == visual) + { + return nxagentDefaultColormaps[i]; + } + } + + return None; +} + +/* + * This is currently unused. It should serve + * the scope of matching a visual whenever + * a drawable has a different depth than the + * real display. + */ + +Visual *nxagentVisualFromDepth(ScreenPtr pScreen, int depth) +{ + int i; + + for (i = 0; i < pScreen->numVisuals; i++) + { + if (pScreen->visuals[i].nplanes == depth) + { + return nxagentVisual(&pScreen->visuals[i]); + } + } + + return NULL; +} + +/* + * Create a fake 32 bits depth visual and + * initialize it based on the endianess + * of the remote display. + */ + +void nxagentInitAlphaVisual() +{ + nxagentAlphaVisual.visualid = XAllocID(nxagentDisplay); + + /* + * Color masks are referred to bits inside + * the pixel. This is independent from the + * endianess. + */ + + nxagentAlphaVisual.red_mask = 0x00ff0000; + nxagentAlphaVisual.green_mask = 0x0000ff00; + nxagentAlphaVisual.blue_mask = 0x000000ff; + + #ifdef TEST + fprintf(stderr,"nxagentInitAlphaVisual: Set alpha visual with id [0x%lx] mask [0x%lx,0x%lx,0x%lx].\n", + nxagentAlphaVisual.visualid, nxagentAlphaVisual.red_mask, + nxagentAlphaVisual.green_mask, nxagentAlphaVisual.blue_mask); + #endif +} diff --git a/nx-X11/programs/Xserver/hw/nxagent/Visual.h b/nx-X11/programs/Xserver/hw/nxagent/Visual.h new file mode 100644 index 000000000..70799f3f8 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Visual.h @@ -0,0 +1,81 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +Copyright 1993 by Davor Matic + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. Davor Matic makes no representations about +the suitability of this software for any purpose. It is provided "as +is" without express or implied warranty. + +*/ + +#ifndef __Visual_H__ +#define __Visual_H__ + +Visual *nxagentVisual(VisualPtr pVisual); +Visual *nxagentVisualFromID(ScreenPtr pScreen, VisualID visual); +Visual *nxagentVisualFromDepth(ScreenPtr pScreen, int depth); + +Colormap nxagentDefaultVisualColormap(Visual *visual); + +#define nxagentDefaultVisual(pScreen) \ + nxagentVisualFromID((pScreen), (pScreen) -> rootVisual) + +/* + * Visual generated by Xorg and Xfree86 at + * 16-bit depth differs on the bits_per_rgb + * value, so we avoid checking it. + */ + +/* + * Some Solaris X servers uses the color + * masks inverted, so that the red and + * the blue mask are switched. To reconnect + * the session on this displays, we do a + * double check, as workaround. + */ + +#define nxagentCompareVisuals(v1, v2) \ + ((v1).depth == (v2).depth && \ + /*(v1).bits_per_rgb == (v2).bits_per_rgb &&*/ \ + (v1).class == (v2).class && \ + ((v1).red_mask == (v2).red_mask || \ + (v1).red_mask == (v2).blue_mask) && \ + (v1).green_mask == (v2).green_mask && \ + ((v1).blue_mask == (v2).blue_mask || \ + (v1).blue_mask == (v2).red_mask) && \ + (v1).colormap_size == (v2).colormap_size) + +Visual nxagentAlphaVisual; + +void nxagentInitAlphaVisual(); + +#endif /* __Visual_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/Window.c b/nx-X11/programs/Xserver/hw/nxagent/Window.c new file mode 100644 index 000000000..23e1d5452 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Window.c @@ -0,0 +1,3930 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <unistd.h> + +#include "X.h" +#include "Xproto.h" +#include "gcstruct.h" +#include "../../include/window.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "colormapst.h" +#include "scrnintstr.h" +#include "region.h" +#include "dixstruct.h" +#include "selection.h" +#include "mi.h" +#include "fb.h" +#include "mibstorest.h" + +#include "Agent.h" +#include "Display.h" +#include "Screen.h" +#include "GCs.h" +#include "GCOps.h" +#include "Drawable.h" +#include "Colormap.h" +#include "Cursor.h" +#include "Visual.h" +#include "Events.h" +#include "Clipboard.h" +#include "Args.h" +#include "Trap.h" +#include "Rootless.h" +#include "Atoms.h" +#include "Client.h" +#include "Reconnect.h" +#include "Dialog.h" +#include "Splash.h" +#include "Holder.h" +#include "Init.h" +#include "Composite.h" +#include "Events.h" + +#include <nx/NX.h> +#include "compext/Compext.h" + +#include "Xatom.h" + +/* + * Used to register the window's privates. + */ + +int nxagentWindowPrivateIndex; + +/* + * Number of windows which need synchronization. + */ + +int nxagentCorruptedWindows; + +/* + * Used to track nxagent window's visibility. + */ + +int nxagentVisibility = VisibilityUnobscured; +unsigned long nxagentVisibilityTimeout = 0; +Bool nxagentVisibilityStop = False; + +/* + * Set here the required log level. + */ + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +/* + * Useful to test the window configuration + * failures. + */ + +#ifdef TEST +#define MAKE_SYNC_CONFIGURE_WINDOW XSync(nxagentDisplay, 0) +#else +#define MAKE_SYNC_CONFIGURE_WINDOW +#endif + +extern WindowPtr nxagentViewportFrameLeft; +extern WindowPtr nxagentViewportFrameRight; +extern WindowPtr nxagentViewportFrameAbove; +extern WindowPtr nxagentViewportFrameBelow; + +extern WindowPtr nxagentRootTileWindow; + +/* + * Also referenced in Events.c. + */ + +int nxagentSplashCount = 0; + +#define RECTLIMIT 25 +#define BSPIXMAPLIMIT 128 + +Bool nxagentExposeArrayIsInitialized = False; +Window nxagentConfiguredSynchroWindow; +static int nxagentExposeSerial = 0; + +StoringPixmapPtr nxagentBSPixmapList[BSPIXMAPLIMIT]; + +/* + * Used to walk through the window hierarchy + * to find a window + */ + +typedef struct _WindowMatch +{ + WindowPtr pWin; + Window id; + +} WindowMatchRec; + +Bool nxagentReconnectAllWindows(void *); + +Bool nxagentDisconnectAllWindows(void); + +Bool nxagentIsIconic(WindowPtr); + +/* + * From NXproperty.c. + */ + +int GetWindowProperty(WindowPtr, Atom, long, long, Bool, Atom, Atom*, int*, + unsigned long*, unsigned long*, unsigned char**); + +/* + * From NXwindow.c. + */ + +void nxagentClearSplash(WindowPtr pWin); + +/* + * Other local functions. + */ + +static Bool nxagentSomeWindowsAreMapped(void); + +static void nxagentFrameBufferPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what); + +static void nxagentTraverseWindow(WindowPtr, void(*)(void *, XID, void *), void *); + +static void nxagentDisconnectWindow(void *, XID, void *); + +static Bool nxagentLoopOverWindows(void(*)(void *, XID, void *)); + +static void nxagentReconfigureWindowCursor(void *, XID, void *); + +static void nxagentReconnectWindow(void *, XID, void *); + +static void nxagentReconfigureWindow(void *, XID, void *); + +static int nxagentForceExposure(WindowPtr pWin, void * ptr); + +/* by dimbor */ +typedef struct +{ + CARD32 state; + Window icon; +} +nxagentWMStateRec; + +/* + * This is currently unused. + */ + +#ifdef TEST + +static Bool nxagentCheckWindowIntegrity(WindowPtr pWin); + +#endif + +WindowPtr nxagentGetWindowFromID(Window id) +{ + WindowPtr pWin = screenInfo.screens[0]->root; + + while (pWin && nxagentWindowPriv(pWin)) + { + if (nxagentWindow(pWin) == id) + { + return pWin; + } + + if (pWin -> nextSib) + { + pWin = pWin -> nextSib; + } + else + { + pWin = pWin -> firstChild; + } + } + + return NULL; +} + +static int nxagentFindWindowMatch(WindowPtr pWin, void * ptr) +{ + WindowMatchRec *match = (WindowMatchRec *) ptr; + + if (match -> id == nxagentWindow(pWin)) + { + match -> pWin = pWin; + + return WT_STOPWALKING; + } + else + { + return WT_WALKCHILDREN; + } +} + +WindowPtr nxagentWindowPtr(Window window) +{ + int i; + + WindowMatchRec match; + + match.pWin = NullWindow; + match.id = window; + + for (i = 0; i < nxagentNumScreens; i++) + { + WalkTree(screenInfo.screens[i], nxagentFindWindowMatch, (void *) &match); + + if (match.pWin) break; + } + + return match.pWin; +} + +Bool nxagentCreateWindow(pWin) + WindowPtr pWin; +{ + unsigned long mask; + XSetWindowAttributes attributes; + Visual *visual; + ColormapPtr pCmap; + + if (nxagentScreenTrap) + { + return True; + } + + nxagentSplashCount++; + + if (nxagentSplashCount == 2) + { + nxagentClearSplash(nxagentRootTileWindow); + } +#ifdef NXAGENT_LOGO_DEBUG + fprintf(stderr, "nxagentSplashCount: %d\n", nxagentSplashCount); +#endif + + if (pWin->drawable.class == InputOnly) { + mask = CWEventMask; + visual = CopyFromParent; + } + else { + mask = CWEventMask | CWBackingStore; + + if (pWin->optional) + { + mask |= CWBackingPlanes | CWBackingPixel; + attributes.backing_planes = pWin->optional->backingBitPlanes; + attributes.backing_pixel = pWin->optional->backingPixel; + } + + attributes.backing_store = NotUseful; + + #ifdef TEST + fprintf(stderr, "nxagentCreateWindow: Backing store on window at %p is %d.\n", + (void*)pWin, attributes.backing_store); + #endif + +/* +FIXME: We need to set save under on the real display? +*/ + if (nxagentSaveUnder == True) + { + mask |= CWSaveUnder; + attributes.save_under = False; + } + + if (pWin->parent) { + if (pWin->optional && pWin->optional->visual != wVisual(pWin->parent)) { + visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin)); + mask |= CWColormap; + if (pWin->optional->colormap) { + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP); + attributes.colormap = nxagentColormap(pCmap); + } + else + attributes.colormap = nxagentDefaultVisualColormap(visual); + } + else if (pWin->optional) + visual = CopyFromParent; + else { + visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin)); + mask |= CWColormap; + attributes.colormap = nxagentDefaultVisualColormap(visual); + } + } + else { /* root windows have their own colormaps at creation time */ + visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin)); + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP); + mask |= CWColormap; + attributes.colormap = nxagentColormap(pCmap); + } + } + + if (mask & CWEventMask) + { + /* Assume that the mask fits in int... broken on Big Endian 64bit systems. */ + Mask tmp_mask = attributes.event_mask; + nxagentGetEventMask(pWin, &tmp_mask); + attributes.event_mask = (int)tmp_mask; + } + #ifdef WARNING + else + { + attributes.event_mask = NoEventMask; + } + #endif + + /* + * Select the event mask if window is a top level + * window. This at least makes the keyboard barely + * work. + */ + + #ifdef TEST + fprintf(stderr, "nxagentCreateWindow: Going to create new window.\n"); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentCreateWindow: Creating %swindow at %p current event mask = %lX mask & CWEventMask = %ld " + "event_mask = %lX\n", + nxagentWindowTopLevel(pWin) ? "toplevel " : "", (void*)pWin, pWin -> eventMask, + mask & CWEventMask, attributes.event_mask); + + fprintf(stderr, "nxagentCreateWindow: position [%d,%d] size [%d,%d] depth [%d] border [%d] class [%d].\n", + pWin->origin.x - wBorderWidth(pWin), pWin->origin.y - wBorderWidth(pWin), + pWin->drawable.width, pWin->drawable.height, pWin->drawable.depth, pWin->borderWidth, + pWin->drawable.class); + #endif + + nxagentWindowPriv(pWin)->window = XCreateWindow(nxagentDisplay, + nxagentWindowParent(pWin), + pWin->origin.x - + wBorderWidth(pWin), + pWin->origin.y - + wBorderWidth(pWin), + pWin->drawable.width, + pWin->drawable.height, + pWin->borderWidth, + pWin->drawable.depth, + pWin->drawable.class, + visual, + mask, &attributes); + + nxagentWindowPriv(pWin) -> isMapped = 0; + nxagentWindowPriv(pWin) -> isRedirected = 0; + + nxagentWindowPriv(pWin) -> visibilityState = VisibilityUnobscured; + + nxagentWindowPriv(pWin) -> corruptedRegion = RegionCreate(NULL, 1); + + nxagentWindowPriv(pWin) -> hasTransparentChildren = 0; + + nxagentWindowPriv(pWin) -> containGlyphs = 0; + + nxagentWindowPriv(pWin) -> corruptedId = 0; + + nxagentWindowPriv(pWin) -> deferredBackgroundExpose = 0; + + nxagentWindowPriv(pWin) -> synchronizationBitmap = NullPixmap; + + nxagentWindowPriv(pWin) -> corruptedTimestamp = 0; + + nxagentWindowPriv(pWin) -> splitResource = NULL; + + if (nxagentOption(Rootless) == 1) + { + if (pWin != nxagentRootlessWindow) + { + WindowPtr pParent = pWin -> parent; + + if (pParent && nxagentWindowPriv(pParent) -> isMapped == 1) + { + nxagentWindowPriv(pWin) -> isMapped = 1; + } + else + { + nxagentWindowPriv(pWin) -> isMapped = 0; + } + } + else + { + nxagentWindowPriv(pWin) -> isMapped = 0; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentCreateWindow: Created new window with id [%ld].\n", + nxagentWindowPriv(pWin)->window); + #endif + + /* + * Set the WM_DELETE_WINDOW protocols on every + * top level window. Also redirect the window + * if it is a top level. + */ + + if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin)) + { + Atom prop = nxagentMakeAtom("WM_PROTOCOLS", strlen("WM_PROTOCOLS"), True); + + XlibAtom atom = nxagentMakeAtom("WM_DELETE_WINDOW", strlen("WM_DELETE_WINDOW"), True); + + XSetWMProtocols(nxagentDisplay, nxagentWindowPriv(pWin)->window, &atom, 1); + + nxagentAddPropertyToList(prop, pWin); + + /* + * Redirect the window to the off-screen + * memory, if the composite extension is + * supported on the display. + */ +/* +FIXME: Do all the windows for which nxagentWindowTopLevel(pWin) + returns true need to be redirected? +*/ + nxagentRedirectWindow(pWin); + } + + nxagentWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin); + nxagentWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin); + nxagentWindowPriv(pWin)->width = pWin->drawable.width; + nxagentWindowPriv(pWin)->height = pWin->drawable.height; + nxagentWindowPriv(pWin)->borderWidth = pWin->borderWidth; + nxagentWindowPriv(pWin)->siblingAbove = None; + nxagentWindowPriv(pWin)->pPicture = NULL; + + if (nxagentRootTileWindow) + { + if (nxagentWindowPriv(pWin)->window != nxagentWindowPriv(nxagentRootTileWindow)->window) + { + XClearWindow(nxagentDisplay, nxagentWindowPriv(nxagentRootTileWindow)->window); + } + } + + if (pWin->nextSib) + { + nxagentWindowPriv(pWin->nextSib)->siblingAbove = nxagentWindow(pWin); + } + +#ifdef NXAGENT_SHAPE2 +#ifdef SHAPE + nxagentWindowPriv(pWin)->boundingShape = NULL; + nxagentWindowPriv(pWin)->clipShape = NULL; +#endif /* SHAPE */ +#else +#ifdef SHAPE + nxagentWindowPriv(pWin)->boundingShape = RegionCreate(NULL, 1); + nxagentWindowPriv(pWin)->clipShape = RegionCreate(NULL, 1); +#endif /* SHAPE */ +#endif + + fbCreateWindow(pWin); + + /* + * Only the root window will have + * the right colormap. + */ + + if (!pWin->parent) + { + nxagentSetInstalledColormapWindows(pWin->drawable.pScreen); + } + + return True; +} + +Bool nxagentSomeWindowsAreMapped() +{ + WindowPtr pWin = screenInfo.screens[0]->root -> firstChild; + + while (pWin) + { + if ((pWin -> mapped || nxagentIsIconic(pWin)) && + pWin -> drawable.class == InputOutput) + { + return True; + } + + pWin = pWin -> nextSib; + } + + return False; +} + +Bool nxagentDestroyWindow(WindowPtr pWin) +{ + int i; + int j; + + nxagentPrivWindowPtr pWindowPriv; + + if (nxagentScreenTrap == 1) + { + return 1; + } + + nxagentClearClipboard(NULL, pWin); + + for (j = 0; j < nxagentExposeQueue.length; j++) + { + i = (nxagentExposeQueue.start + j) % EXPOSED_SIZE; + + if (nxagentExposeQueue.exposures[i].pWindow == pWin) + { + if (nxagentExposeQueue.exposures[i].localRegion != NullRegion) + { + RegionDestroy(nxagentExposeQueue.exposures[i].localRegion); + } + + nxagentExposeQueue.exposures[i].localRegion = NullRegion; + + if (nxagentExposeQueue.exposures[i].remoteRegion != NullRegion) + { + RegionDestroy(nxagentExposeQueue.exposures[i].remoteRegion); + } + + nxagentExposeQueue.exposures[i].remoteRegion = NullRegion; + } + } + + nxagentDeleteConfiguredWindow(pWin); + + pWindowPriv = nxagentWindowPriv(pWin); + + if (pWin->nextSib) + { + nxagentWindowPriv(pWin->nextSib)->siblingAbove = + pWindowPriv->siblingAbove; + } + + #ifdef NXAGENT_SHAPE2 + + #ifdef SHAPE + + if (pWindowPriv->boundingShape) + { + RegionDestroy( + pWindowPriv->boundingShape); + } + + if (pWindowPriv->clipShape) + { + RegionDestroy( + pWindowPriv->clipShape); + } + + #endif + + #else + + RegionDestroy( + pWindowPriv->boundingShape); + + RegionDestroy( + pWindowPriv->clipShape); + + #endif + + if (pWindowPriv -> corruptedRegion) + { + RegionDestroy( + pWindowPriv -> corruptedRegion); + + pWindowPriv -> corruptedRegion = NULL; + } + + if (nxagentSynchronization.pDrawable == (DrawablePtr) pWin) + { + nxagentSynchronization.pDrawable = NULL; + + #ifdef TEST + fprintf(stderr, "nxagentDestroyWindow: Synchronization drawable [%p] removed from resources.\n", + (void *) pWin); + #endif + } + + nxagentDestroyCorruptedResource((DrawablePtr) pWin, RT_NX_CORR_WINDOW); + + nxagentDestroyDrawableBitmap((DrawablePtr) pWin); + + if (pWindowPriv -> splitResource != NULL) + { + nxagentReleaseSplit((DrawablePtr) pWin); + } + + XDestroyWindow(nxagentDisplay, nxagentWindow(pWin)); + + if (nxagentOption(Rootless)) + { + nxagentRootlessDelTopLevelWindow(pWin); + } + + nxagentSplashCount--; + + #ifdef DEBUG + fprintf(stderr, "nxagentDestroyWindow: The splash counter is now [%d].\n", + nxagentSplashCount); + #endif + + if (nxagentSplashCount == 1) + { + XClearWindow(nxagentDisplay, nxagentWindowPriv(nxagentRootTileWindow) -> window); + } + + if (pWin == nxagentRootTileWindow) + { + nxagentWindowPriv(nxagentRootTileWindow)->window = None; + + nxagentRootTileWindow = None; + } + + pWindowPriv->window = None; + + if (pWin -> optional) + { + pWin -> optional -> userProps = NULL; + } + + if (nxagentOption(Rootless) && nxagentRootlessDialogPid == 0 && + nxagentLastWindowDestroyed == False && nxagentSomeWindowsAreMapped() == False) + { + #ifdef TEST + fprintf(stderr, "nxagentDestroyWindow: Last mapped window as been destroyed.\n"); + #endif + + nxagentLastWindowDestroyed = True; + nxagentLastWindowDestroyedTime = GetTimeInMillis(); + } + + return True; +} + +Bool nxagentPositionWindow(WindowPtr pWin, int x, int y) +{ + if (nxagentScreenTrap == 1) + { + return True; + } + + #ifdef TEST + fprintf(stderr, "nxagentPositionWindow: Changing position of window [%p][%ld] to [%d,%d].\n", + (void *) pWin, nxagentWindow(pWin), x, y); + #endif + + nxagentAddConfiguredWindow(pWin, CWParent | CWX | CWY | CWWidth | + CWHeight | CWBorderWidth); + + return True; +} + +void nxagentRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib) +{ + if (nxagentScreenTrap == 1) + { + return; + } + + nxagentAddConfiguredWindow(pWin, CW_RootlessRestack); + +} + +void nxagentSwitchFullscreen(ScreenPtr pScreen, Bool switchOn) +{ + XEvent e; + + if (nxagentOption(Rootless) == 1) + { + return; + } + + if (switchOn == 0) + { + nxagentWMDetect(); + + /* + * The smart scheduler could be stopped while + * waiting for the reply. In this case we need + * to yield explicitly to avoid to be stuck in + * the dispatch loop forever. + */ + + isItTimeToYield = 1; + + if (nxagentWMIsRunning == 0) + { + #ifdef WARNING + fprintf(stderr, "Warning: Can't switch to window mode, no window manager " + "has been detected.\n"); + #endif + + return; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentSwitchFullscreen: Switching to %s mode.\n", + switchOn ? "fullscreen" : "windowed"); + #endif + + nxagentChangeOption(Fullscreen, switchOn); + + memset(&e, 0, sizeof(e)); + + e.xclient.type = ClientMessage; + e.xclient.message_type = nxagentAtoms[13]; /* _NET_WM_STATE */ + e.xclient.display = nxagentDisplay; + e.xclient.window = nxagentDefaultWindows[pScreen -> myNum]; + e.xclient.format = 32; + e.xclient.data.l[0] = nxagentOption(Fullscreen) ? 1 : 0; + e.xclient.data.l[1] = nxagentAtoms[14]; /* _NET_WM_STATE_FULLSCREEN */ + + XSendEvent(nxagentDisplay, DefaultRootWindow(nxagentDisplay), False, + SubstructureRedirectMask, &e); + + if (switchOn == 1) + { + nxagentFullscreenWindow = nxagentDefaultWindows[pScreen -> myNum]; + + nxagentGrabPointerAndKeyboard(NULL); + } + else + { + nxagentFullscreenWindow = None; + + nxagentUngrabPointerAndKeyboard(NULL); + } +} + +void nxagentSwitchAllScreens(ScreenPtr pScreen, Bool switchOn) +{ + Window w; + XSetWindowAttributes attributes; + unsigned long valuemask; + + if (nxagentOption(Rootless)) + { + return; + } + + if (!switchOn) + { + nxagentWMDetect(); + + if (!nxagentWMIsRunning) + { + #ifdef WARNING + fprintf(stderr, "Warning: Can't switch to window mode, no window manager has been detected.\n"); + #endif + + return; + } + } + + w = nxagentDefaultWindows[pScreen -> myNum]; + attributes.override_redirect = switchOn; + valuemask = CWOverrideRedirect; + XUnmapWindow(nxagentDisplay, w); + XChangeWindowAttributes(nxagentDisplay, w, valuemask, &attributes); + + XReparentWindow(nxagentDisplay, w, DefaultRootWindow(nxagentDisplay), 0, 0); + + if (switchOn) + { + /* + * Change to fullscreen mode. + */ + + struct timeval timeout; + int i; + XEvent e; + + /* + * Wait for window manager reparenting the default window. + */ + + for (i = 0; i < 100 && nxagentWMIsRunning; i++) + { + #ifdef TEST + fprintf(stderr, "nxagentSwitchAllScreens: WARNING! Going to wait for the ReparentNotify event.\n"); + #endif + + if (XCheckTypedWindowEvent(nxagentDisplay, w, ReparentNotify, &e)) + { + break; + } + + /* + * This should also flush + * the NX link for us. + */ + + XSync(nxagentDisplay, 0); + + timeout.tv_sec = 0; + timeout.tv_usec = 50 * 1000; + + nxagentWaitEvents(nxagentDisplay, &timeout); + } + + if (i < 100) + { + /* + * The window manager has done with the reparent + * operation. We can resize and map the window. + */ + + nxagentChangeOption(Fullscreen, True); + nxagentChangeOption(AllScreens, True); + + + /* + * Save the window-mode configuration. + */ + + nxagentChangeOption(SavedX, nxagentOption(X)); + nxagentChangeOption(SavedY, nxagentOption(Y)); + nxagentChangeOption(SavedWidth, nxagentOption(Width)); + nxagentChangeOption(SavedHeight, nxagentOption(Height)); + nxagentChangeOption(SavedRootWidth, nxagentOption(RootWidth)); + nxagentChangeOption(SavedRootHeight, nxagentOption(RootHeight)); + + /* + * Reconf the Default window. + */ + + nxagentChangeOption(X, 0); + nxagentChangeOption(Y, 0); + nxagentChangeOption(Width, WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay))); + nxagentChangeOption(Height, HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay))); + + /* + * Move the root window. + */ + + nxagentChangeOption(RootX, (nxagentOption(Width) - nxagentOption(RootWidth)) / 2); + nxagentChangeOption(RootY, (nxagentOption(Height) - nxagentOption(RootHeight)) / 2); + nxagentChangeOption(ViewportXSpan, nxagentOption(Width) - nxagentOption(RootWidth)); + nxagentChangeOption(ViewportYSpan, nxagentOption(Height) - nxagentOption(RootHeight)); + + XMoveResizeWindow(nxagentDisplay, w, nxagentOption(X), nxagentOption(Y), + nxagentOption(Width), nxagentOption(Height)); + + nxagentUpdateViewportFrame(0, 0, nxagentOption(RootWidth), nxagentOption(RootHeight)); + + XMoveWindow(nxagentDisplay, nxagentWindow(pScreen->root), + nxagentOption(RootX), nxagentOption(RootY)); + + /* + * We disable the screensaver when changing + * mode to fullscreen. Is it really needed? + */ + + XSetScreenSaver(nxagentDisplay, 0, 0, DefaultExposures, DefaultBlanking); + + if (nxagentIconWindow == None) + { + nxagentIconWindow = nxagentCreateIconWindow(); + + XMapWindow(nxagentDisplay, nxagentIconWindow); + } + + XMapRaised(nxagentDisplay, w); + XSetInputFocus(nxagentDisplay, w, RevertToParent, CurrentTime); + XCheckTypedWindowEvent(nxagentDisplay, w, LeaveNotify, &e); + nxagentFullscreenWindow = w; + + if (nxagentOption(DesktopResize) == 1) + { + if (nxagentOption(Shadow) == 0) + { + nxagentChangeScreenConfig(0, WidthOfScreen(DefaultScreenOfDisplay(nxagentDisplay)), + HeightOfScreen(DefaultScreenOfDisplay(nxagentDisplay)), 0, 0); + } + else + { + nxagentShadowAdaptToRatio(); + } + } + } + else + { + /* + * We have waited for a reparent event unsuccessfully. + * Something happened to the window manager. + */ + + #ifdef WARNING + fprintf(stderr, "nxagentSwitchAllScreens: WARNING! Expected ReparentNotify event missing.\n"); + #endif + + nxagentWMIsRunning = False; + attributes.override_redirect = False; + XChangeWindowAttributes(nxagentDisplay, w, valuemask, &attributes); + XMapWindow(nxagentDisplay, w); + } + } + else + { + /* + * FIXME: + * It could be necessary: + * - To restore screensaver. + * - To set or reset nxagentForceBackingStore flag. + * - To propagate device settings to the X server if no WM is running. + */ + + /* + * Change to windowed mode. + */ + + nxagentChangeOption(Fullscreen, False); + nxagentChangeOption(AllScreens, False); + + XDestroyWindow(nxagentDisplay, nxagentIconWindow); + + nxagentIconWindow = nxagentFullscreenWindow = None; + + if (nxagentOption(DesktopResize) == 1) + { + nxagentChangeOption(RootWidth, nxagentOption(SavedRootWidth)); + nxagentChangeOption(RootHeight, nxagentOption(SavedRootHeight)); + + if (nxagentOption(Shadow) == 0) + { + nxagentChangeScreenConfig(0, nxagentOption(RootWidth), + nxagentOption(RootHeight), 0, 0); + } + } + + if (nxagentOption(WMBorderWidth) > 0 && nxagentOption(WMTitleHeight) > 0) + { + nxagentChangeOption(X, nxagentOption(SavedX) - + nxagentOption(WMBorderWidth)); + nxagentChangeOption(Y, nxagentOption(SavedY) - + nxagentOption(WMTitleHeight)); + } + else + { + nxagentChangeOption(X, nxagentOption(SavedX)); + nxagentChangeOption(Y, nxagentOption(SavedY)); + } + + nxagentChangeOption(Width, nxagentOption(SavedWidth)); + nxagentChangeOption(Height, nxagentOption(SavedHeight)); + + if (nxagentOption(Shadow) == 1 && nxagentOption(DesktopResize) == 1) + { + nxagentShadowAdaptToRatio(); + } + + XMoveResizeWindow(nxagentDisplay, w, nxagentOption(X), nxagentOption(Y), + nxagentOption(Width), nxagentOption(Height)); + + nxagentUpdateViewportFrame(0, 0, nxagentOption(Width), nxagentOption(Height)); + + XMoveWindow(nxagentDisplay, nxagentWindow(pScreen->root), 0, 0); + XMapWindow(nxagentDisplay, w); + + nxagentChangeOption(RootX, 0); + nxagentChangeOption(RootY, 0); + } + + XMoveResizeWindow(nxagentDisplay, nxagentInputWindows[0], 0, 0, + nxagentOption(Width), nxagentOption(Height)); + + nxagentSetPrintGeometry(pScreen -> myNum); +} + +#ifdef VIEWPORT_FRAME + +void nxagentUpdateViewportFrame(int x, int y, int w, int h) +{ + /* + * Four virtual windows make a frame around the viewport. We move the frame + * with the viewport together. The areas going into the viewport were covered by + * the frame and become exposed. This make the agent send expose events to his + * clients. + */ + + XID values[3]; + Mask mask; + + /* + * nxagentScreenTrap = True; + */ + + values[2] = Above; + + values[1] = nxagentOption(RootHeight); + + mask = CWX | CWHeight | CWStackMode; + values[0] = x - NXAGENT_FRAME_WIDTH; + ConfigureWindow(nxagentViewportFrameLeft, mask, (XID *) &values, serverClient); + + values[0] = x + w; + ConfigureWindow(nxagentViewportFrameRight, mask, (XID *) &values, serverClient); + + values[1] = nxagentOption(RootWidth); + + mask = CWY | CWWidth | CWStackMode; + values[0] = y - NXAGENT_FRAME_WIDTH; + ConfigureWindow(nxagentViewportFrameAbove, mask, (XID *) &values, serverClient); + + values[0] = y + h; + ConfigureWindow(nxagentViewportFrameBelow, mask, (XID *) &values, serverClient); + + /* + * nxagentScreenTrap = False; + */ +} + +#endif /* #ifdef VIEWPORT_FRAME */ + +void nxagentMoveViewport(ScreenPtr pScreen, int hShift, int vShift) +{ + int newX; + int newY; + int oldX; + int oldY; + + Bool doMove = False; + oldX = 0; + oldY = 0; + + if (nxagentOption(Rootless)) + { + return; + } + + /* + * We must keep x coordinate between viewportXSpan and zero, if viewportXSpan + * is less then zero. If viewportXSpan is greater or equal to zero, it means + * the agent root window has a size smaller than the agent default window. + * In this case we keep the old coordinate. + */ + + #ifdef DEBUG + fprintf(stderr, "nxagentMoveViewport: RootX[%i] RootY[%i], hShift[%i] vShift[%i].\n", + nxagentOption(RootX), nxagentOption(RootY), hShift, vShift); + #endif + + nxagentChangeOption(ViewportXSpan, nxagentOption(Width) - nxagentOption(RootWidth)); + + nxagentChangeOption(ViewportYSpan, nxagentOption(Height) - nxagentOption(RootHeight)); + + if (nxagentOption(ViewportXSpan) < 0) + { + newX = nxagentOption(RootX) - hShift; + + if (newX > 0) + { + newX = 0; + } + else if (newX < nxagentOption(ViewportXSpan)) + { + newX = nxagentOption(ViewportXSpan); + } + } + else if (nxagentOption(ViewportXSpan) == 0) + { + newX = 0; + } + else + { + newX = nxagentOption(RootX); + } + + if (nxagentOption(ViewportYSpan) < 0) + { + newY = nxagentOption(RootY) - vShift; + + if (newY > 0) + { + newY = 0; + } + else if (newY < nxagentOption(ViewportYSpan)) + { + newY = nxagentOption(ViewportYSpan); + } + } + else if (nxagentOption(ViewportYSpan) == 0) + { + newY = 0; + } + else + { + newY = nxagentOption(RootY); + } + + oldX = nxagentOption(RootX); + + if (newX != nxagentOption(RootX)) + { + nxagentChangeOption(RootX, newX); + + doMove = True; + } + + oldY = nxagentOption(RootY); + + if (newY != nxagentOption(RootY)) + { + nxagentChangeOption(RootY, newY); + + doMove = True; + } + + if (doMove) + { + #ifdef TEST + fprintf(stderr, "nxagentMoveViewport: New viewport geometry: (%d, %d)-" + "(%d, %d)\n", -nxagentOption(RootX), -nxagentOption(RootY), + -nxagentOption(RootX) + nxagentOption(Width), + -nxagentOption(RootY) + nxagentOption(Height)); + + fprintf(stderr, "nxagentMoveViewport: Root geometry x=[%d] y=[%d]\n", + pScreen->root -> drawable.x, + pScreen->root -> drawable.y ); + #endif + + XMoveWindow(nxagentDisplay, nxagentWindow(pScreen->root), + nxagentOption(RootX), nxagentOption(RootY)); + + if (nxagentOption(ClientOs) == ClientOsWinnt) + { + /* + * If doMove is True we add exposed rectangles + * to the remote expose region. This is done to + * refresh the areas showed newly in the viewport. + * We create two rectangles, one for horizontal + * pan and one for vertical pan. + */ + + BoxRec hRect; + BoxRec vRect; + + hRect.x1 = -newX; + hRect.y1 = -newY; + + if (hShift < 0) + { + hRect.x2 = -oldX; + hRect.y2 = -newY + nxagentOption(Height); + } + else if (hShift > 0) + { + hRect.x1 = -oldX + nxagentOption(Width); + hRect.x2 = -newX + nxagentOption(Width); + hRect.y2 = -newY + nxagentOption(Height); + } + + #ifdef DEBUG + fprintf(stderr, "nxagentMoveViewport: hRect p1[%i, %i] - p2[%i, %i].\n", hRect.x1, hRect.y1, hRect.x2, hRect.y2); + #endif + + vRect.x1 = -newX; + vRect.y1 = -newY; + + if (vShift < 0) + { + vRect.x2 = -newX + nxagentOption(Width); + vRect.y2 = -oldY; + } + else if (vShift > 0) + { + vRect.y1 = -oldY + nxagentOption(Height); + vRect.x2 = -newX + nxagentOption(Width); + vRect.y2 = -newY + nxagentOption(Height); + } + + #ifdef DEBUG + fprintf(stderr, "nxagentMoveViewport: vRect p1[%i, %i] - p2[%i, %i].\n", vRect.x1, vRect.y1, vRect.x2, vRect.y2); + #endif + + if (oldX != newX && hRect.x1 != hRect.x2 && hRect.y1 != hRect.y2) + { + nxagentAddRectToRemoteExposeRegion(&hRect); + } + + if (oldY != newY && vRect.x1 != vRect.x2 && vRect.y1 != vRect.y2) + { + nxagentAddRectToRemoteExposeRegion(&vRect); + } + } + } + + nxagentUpdateViewportFrame(-nxagentOption(RootX), -nxagentOption(RootY), + nxagentOption(Width), nxagentOption(Height)); +} + +void nxagentConfigureWindow(WindowPtr pWin, unsigned int mask) +{ + unsigned int valuemask; + XWindowChanges values; + int offX, offY; + int i, j; + + offX = nxagentWindowPriv(pWin)->x - pWin->origin.x; + offY = nxagentWindowPriv(pWin)->y - pWin->origin.y; + + if (nxagentScreenTrap == 1) + { + #ifdef TEST + fprintf(stderr, "nxagentConfigureWindow: WARNING: Called with the screen trap set.\n"); + #endif + + return; + } + + if (nxagentOption(Rootless) == 1 && + nxagentWindowTopLevel(pWin) == 1) + { + mask &= ~(CWSibling | CWStackMode); + } + else + { + if (mask & CW_RootlessRestack) + { + mask = CWStackingOrder; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentConfigureWindow: Called with window [%p][%ld] and mask [%x].\n", + (void *) pWin, nxagentWindow(pWin), mask); + #endif + + nxagentMoveCorruptedRegion(pWin, mask); + + valuemask = 0; + + if (mask & CW_Update) + { + mask |= CWX | CWY | CWWidth | CWHeight | CWBorderWidth | CWStackingOrder; + } + + if (mask & CWX) + { + valuemask |= CWX; + + values.x = nxagentWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin); + } + + if (mask & CWY) + { + valuemask |= CWY; + + values.y = nxagentWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin); + } + + if (mask & CWWidth) + { + valuemask |= CWWidth; + + values.width = nxagentWindowPriv(pWin)->width = pWin->drawable.width; + } + + if (mask & CWHeight) + { + valuemask |= CWHeight; + + values.height = nxagentWindowPriv(pWin)->height = pWin->drawable.height; + } + + if (mask & CWBorderWidth) + { + valuemask |= CWBorderWidth; + + values.border_width = nxagentWindowPriv(pWin)->borderWidth = + pWin->borderWidth; + } + + if (mask & CW_Update) + { + valuemask = 0; + } + + if (valuemask) + { + #ifdef TEST + fprintf(stderr, "nxagentConfigureWindow: Going to configure window [%p][%ld] with mask [%x].\n", + (void *) pWin, nxagentWindow(pWin), valuemask); + #endif + + if (pWin->bitGravity == StaticGravity && + ((mask & CWX) || (mask & CWY)) && + ((mask & CWWidth) || (mask & CWHeight))) + { + #ifdef TEST + fprintf(stderr, "nxagentConfigureWindow: Window has StaticGravity. Going to translate Expose events by offset [%d, %d].\n", + offX, offY); + #endif + + nxagentAddStaticResizedWindow(pWin, XNextRequest(nxagentDisplay), offX, offY); + + for (j = 0; j < nxagentExposeQueue.length; j++) + { + i = (nxagentExposeQueue.start + j) % EXPOSED_SIZE; + + if (nxagentExposeQueue.exposures[i].pWindow == pWin && + nxagentExposeQueue.exposures[i].remoteRegion != NullRegion) + { + RegionTranslate(nxagentExposeQueue.exposures[i].remoteRegion, offX, offY); + } + } + } + + XConfigureWindow(nxagentDisplay, nxagentWindow(pWin), valuemask, &values); + + MAKE_SYNC_CONFIGURE_WINDOW; + } + + if (mask & CWStackingOrder && + nxagentWindowPriv(pWin)->siblingAbove != nxagentWindowSiblingAbove(pWin)) + { + WindowPtr pSib; + + /* + * Find the top sibling. + */ + + for (pSib = pWin; pSib->prevSib != NullWindow; pSib = pSib->prevSib); + + /* + * Configure the top sibling. + */ + + valuemask = CWStackMode; + + values.stack_mode = Above; + + #ifdef TEST + fprintf(stderr, "nxagentConfigureWindow: Going to configure top sibling [%ld] " + "with mask [%x] and parent [%ld].\n", nxagentWindow(pSib), + valuemask, nxagentWindowParent(pWin)); + #endif + + XConfigureWindow(nxagentDisplay, nxagentWindow(pSib), valuemask, &values); + + MAKE_SYNC_CONFIGURE_WINDOW; + + nxagentWindowPriv(pSib)->siblingAbove = None; + + /* + * Configure the rest of siblings. + */ + + valuemask = CWSibling | CWStackMode; + + values.stack_mode = Below; + + for (pSib = pSib->nextSib; pSib != NullWindow; pSib = pSib->nextSib) + { + values.sibling = nxagentWindowSiblingAbove(pSib); + + #ifdef TEST + fprintf(stderr, "nxagentConfigureWindow: Going to configure other sibling [%ld] " + "with mask [%x] and parent [%ld] below [%ld].\n", nxagentWindow(pSib), + valuemask, nxagentWindowParent(pWin), nxagentWindowSiblingAbove(pSib)); + #endif + + XConfigureWindow(nxagentDisplay, nxagentWindow(pSib), valuemask, &values); + + MAKE_SYNC_CONFIGURE_WINDOW; + + nxagentWindowPriv(pSib)->siblingAbove = nxagentWindowSiblingAbove(pSib); + } + + #ifdef TEST + { + Window root_return; + Window parent_return; + Window *children_return; + unsigned int nchildren_return; + Window *pw; + Status result; + + result = XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay), + &root_return, &parent_return, &children_return, &nchildren_return); + + if (result) + { + pw = children_return; + + fprintf(stderr, "nxagentConfigureWindow: Children of the root: "); + while(nchildren_return > 0) + { + pSib = nxagentWindowPtr(children_return[--nchildren_return]); + if (pSib) + { + fprintf(stderr, "%lu ", children_return[nchildren_return]); + } + } + fprintf(stderr, "\n"); + + if (children_return) + { + XFree(children_return); + } + } + else + { + fprintf(stderr, "nxagentConfigureWindow: Failed QueryTree request.\n "); + } + } + #endif + } + + #ifdef NXAGENT_SPLASH + + /* + * This should bring again the splash window + * on top, so why the else clause? Is this + * really needed? + * + * + * else if (mask & CWStackingOrder) + * { + * if (nxagentSplashWindow) + * { + * valuemask = CWStackMode; + * + * values.stack_mode = Above; + * + * #ifdef TEST + * fprintf(stderr, "nxagentConfigureWindow: Going to configure splash window [%ld].\n", + * nxagentSplashWindow); + * #endif + * + * XConfigureWindow(nxagentDisplay, nxagentSplashWindow, valuemask, &values); + * + * MAKE_SYNC_CONFIGURE_WINDOW; + * } + * } + */ + + #endif + + if (mask & CW_RootlessRestack) + { + if (!pWin -> prevSib) + { + #ifdef TEST + fprintf(stderr, "nxagentConfigureWindow: Raising window [%p][%ld].\n", + (void *) pWin, nxagentWindow(pWin)); + #endif + + XRaiseWindow(nxagentDisplay, nxagentWindow(pWin)); + } + else if (!pWin -> nextSib) + { + #ifdef TEST + fprintf(stderr, "nxagentConfigureWindow: Lowering window [%p][%ld].\n", + (void *) pWin, nxagentWindow(pWin)); + #endif + + XLowerWindow(nxagentDisplay, nxagentWindow(pWin)); + } + else + { + XlibWindow windowList[2]; + + #ifdef TEST + fprintf(stderr, "nxagentConfigureWindow: Putting window [%p][%ld] in the middle.\n", + (void *) pWin, nxagentWindow(pWin)); + #endif + + windowList[0] = nxagentWindow(pWin->prevSib); + windowList[1] = nxagentWindow(pWin); + + XRestackWindows(nxagentDisplay, windowList, 2); + } + } + + #ifdef SHAPE + + if (mask & CW_Shape) + { + nxagentShapeWindow(pWin); + } + + #endif + + if (mask & CW_Map && + (!nxagentOption(Rootless) || + nxagentRootlessWindow != pWin)) + { + XMapWindow(nxagentDisplay, nxagentWindow(pWin)); + + return; + } +} + +void nxagentReparentWindow(pWin, pOldParent) + WindowPtr pWin; + WindowPtr pOldParent; +{ + if (nxagentScreenTrap) + { + return; + } + + #ifdef TEST + fprintf(stderr, "nxagentReparentWindow: window at %p [%lx] previous parent at %p [%lx].\n", + (void*)pWin, nxagentWindow(pWin), + (void*)pOldParent, nxagentWindow(pOldParent)); + #endif + + XReparentWindow(nxagentDisplay, nxagentWindow(pWin), + nxagentWindowParent(pWin), + pWin->origin.x - wBorderWidth(pWin), + pWin->origin.y - wBorderWidth(pWin)); +} + +Bool nxagentChangeWindowAttributes(pWin, mask) + WindowPtr pWin; + unsigned long mask; +{ + XSetWindowAttributes attributes; + + #ifdef TEST + fprintf(stderr, "nxagentChangeWindowAttributes: Changing attributes for window at [%p] with mask [%lu].\n", + (void *) pWin, mask); + #endif + + if (nxagentScreenTrap) + { + return True; + } + + if (mask & CWBackPixmap) + { + switch (pWin->backgroundState) + { + case None: + { + attributes.background_pixmap = None; + attributes.background_pixel = nxagentWhitePixel; + + /* + * One of problems faced during the implementation of lazy + * encoding policies was due to the presence of windows with + * transparent background, usually created by X clients to + * cover some sensible areas (i.e. checkboxes used by + * Konqueror 3.5). The sequence of operations consists in + * drawing the underneath part before covering it with the + * transparent window, so when we synchronize the deferred + * drawing operation we have to bear in mind that the dest- + * ination area is covered by a window. By using the Inclu- + * deInferiors GC's property and by clipping the region to + * synchronize to the borderClip instead of clipList (to + * include the areas covered by children) we can easily take + * care of this situation, but there is a drawback: if the + * children are not transparent, we are going to synchronize + * invisible areas. To avoid this we have added the 'has- + * TransparentChildren' flag, which is set when a window has + * at least one child with background None. The problem is + * that we don't know when to reset the flag. This solution, + * also, doesn't take care of transparent windows which don't + * have childhood relationships with underneath windows. + * We tried to mark the whole windows as dirty when they are + * created to force the synchronization of transparent windows + * with the content of underneath windows, but, of course, + * this works only with the first synchronization because the + * transparent windows will be never marked again as dirty. + */ + + if (pWin -> parent != NULL) + { + nxagentWindowPriv(pWin -> parent) -> hasTransparentChildren = 1; + + #ifdef DEBUG + fprintf(stderr, "nxagentChangeWindowAttributes: WARNING! Window at [%p] got the " + "hasTransparentChildren flag.\n", (void *) pWin); + #endif + } + + break; + } + case ParentRelative: + { + attributes.background_pixmap = ParentRelative; + + break; + } + case BackgroundPixmap: + { + /* + * If a window background is corrupted, we grant + * its usability by clearing it with a solid co- + * lor. When the pixmap will be fully synchroni- + * zed, an expose will be sent to the window's + * hierarchy. + */ + + if (nxagentDrawableStatus((DrawablePtr) pWin -> background.pixmap) == NotSynchronized) + { + #ifdef TEST + fprintf(stderr, "nxagentChangeWindowAttributes: The window at [%p] has the background at [%p] " + "not synchronized.\n", (void *) pWin, (void *) pWin -> background.pixmap); + #endif + + if (nxagentIsCorruptedBackground(pWin -> background.pixmap) == 0) + { + nxagentIsCorruptedBackground(pWin -> background.pixmap) = 1; + + nxagentAllocateCorruptedResource((DrawablePtr) pWin -> background.pixmap, RT_NX_CORR_BACKGROUND); + + /* + * Clearing the remote background to + * make it usable. + */ + + nxagentFillRemoteRegion((DrawablePtr) pWin -> background.pixmap, + nxagentCorruptedRegion((DrawablePtr) pWin -> background.pixmap)); + } + } + + attributes.background_pixmap = nxagentPixmap(pWin -> background.pixmap); + + break; + } + case BackgroundPixel: + { + mask &= ~CWBackPixmap; + + break; + } + } + } + + if (mask & CWBackPixel) + { + if (pWin -> backgroundState == BackgroundPixel) + { + attributes.background_pixel = nxagentPixel(pWin -> background.pixel); + } + else + { + mask &= ~CWBackPixel; + } + } + + if (mask & CWBorderPixmap) + { + if (pWin -> borderIsPixel != 0) + { + mask &= ~CWBorderPixmap; + } + else + { + attributes.border_pixmap = nxagentPixmap(pWin -> border.pixmap); + } + } + + if (mask & CWBorderPixel) + { + if (pWin -> borderIsPixel != 0) + { + attributes.border_pixel = nxagentPixel(pWin -> border.pixel); + } + else + { + mask &= ~CWBorderPixel; + } + } + + if (mask & CWBitGravity) + { + attributes.bit_gravity = pWin -> bitGravity; + } + + /* + * As we set this bit, whe must change dix in + * order not to perform PositionWindow and let + * X move children windows for us. + */ + + if (mask & CWWinGravity) + { + attributes.win_gravity = pWin -> winGravity; + } + +/* +FIXME: Do we need to set the attribute on the + remote display? +*/ + if (mask & CWBackingStore) + { + attributes.backing_store = pWin -> backingStore; + + #ifdef TEST + fprintf(stderr, "nxagentChangeWindowAttributes: Changing backing store value to %d" + " for window at %p.\n", pWin -> backingStore, (void*)pWin); + #endif + } + + if (mask & CWBackingPlanes) + { + if ((nxagentBackingStore == NotUseful) || (pWin -> optional == NULL)) + { + mask &= ~CWBackingPlanes; + } + else + { + attributes.backing_planes = pWin -> optional -> backingBitPlanes; + } + } + + if (mask & CWBackingPixel) + { + if ((nxagentBackingStore == NotUseful) || (pWin -> optional == NULL)) + { + mask &= ~CWBackingPixel; + } + else + { + attributes.backing_pixel = pWin -> optional -> backingPixel; + } + } + + if (mask & CWOverrideRedirect) + { + attributes.override_redirect = pWin -> overrideRedirect; + } + +/* +FIXME: Do we need to set the attribute on the + remote display? +*/ + if (mask & CWSaveUnder) + { + attributes.save_under = pWin -> saveUnder; + } + + /* + * Events are handled elsewhere. + */ + + if (mask & CWEventMask) + { + mask &= ~CWEventMask; + } + + if (mask & CWDontPropagate) + { + mask &= ~CWDontPropagate; + } + + if (mask & CWColormap) + { + ColormapPtr pCmap; + + pCmap = (ColormapPtr) LookupIDByType(wColormap(pWin), RT_COLORMAP); + +/* +FIXME: When the caller is nxagentReconfigureWindow + sometimes wColormap(pWin) is 0. Could a window + have no colormap? +*/ + if (pCmap != NULL) + { + attributes.colormap = nxagentColormap(pCmap); + + nxagentSetInstalledColormapWindows(pWin -> drawable.pScreen); + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentChangeWindowAttributes: WARNING! Bad colormap " + "[%lu] for window at [%p].\n", wColormap(pWin), (void *) pWin); + #endif + + mask &= ~CWColormap; + } + } + + if (mask & CWCursor) + { + if (nxagentOption(Rootless)) + { + if (pWin->cursorIsNone == 0 && pWin->optional != NULL && + pWin->optional->cursor != NULL && nxagentCursorPriv(pWin -> + optional -> cursor, pWin -> drawable.pScreen) != NULL) + { + attributes.cursor = nxagentCursor(pWin -> optional -> cursor, + pWin -> drawable.pScreen); + } + else + { + attributes.cursor = None; + } + } + else + { + /* + * This is handled in cursor code + */ + + mask &= ~CWCursor; + } + } + + if (mask != 0) + { + XChangeWindowAttributes(nxagentDisplay, nxagentWindow(pWin), mask, &attributes); + } + + return 1; +} + +Bool nxagentRealizeWindow(WindowPtr pWin) +{ + if (nxagentScreenTrap == 1) + { + return True; + } + + /* + * Not needed. + * + * nxagentConfigureWindow(pWin, CWStackingOrder); + * + * nxagentFlushConfigureWindow(); + */ + + nxagentAddConfiguredWindow(pWin, CWStackingOrder); + nxagentAddConfiguredWindow(pWin, CW_Shape); + + /* add by dimbor */ + if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin)) + { + Atom prop = MakeAtom("WM_STATE", strlen("WM_STATE"), True); + nxagentWMStateRec wmState; + wmState.state = 1; /* NormalState */ + wmState.icon = None; + if (ChangeWindowProperty(pWin, prop, prop, 32, 0, 2, &wmState, 1) != Success) + fprintf(stderr, "nxagentRealizeWindow: Adding WM_STATE fail.\n"); + } + + #ifdef SHAPE + + /* + * Not needed. + * + * nxagentShapeWindow(pWin); + */ + + #endif /* SHAPE */ + + /* + * Mapping of the root window is called by + * InitRootWindow in DIX. Skip the operation + * if we are in rootless mode. + */ + + /* + * if (!nxagentOption(Rootless) || + * nxagentRootlessWindow != pWin) + * { + * XMapWindow(nxagentDisplay, nxagentWindow(pWin)); + * } + */ + + #ifdef TEST + if (nxagentOption(Rootless) && nxagentLastWindowDestroyed) + { + fprintf(stderr, "nxagentRealizeWindow: Window realized. Stopped termination for rootless session.\n"); + } + #endif + + nxagentAddConfiguredWindow(pWin, CW_Map); + + nxagentLastWindowDestroyed = False; + + return True; +} + +Bool nxagentUnrealizeWindow(pWin) + WindowPtr pWin; +{ + if (nxagentScreenTrap) + { + return True; + } + + /* add by dimbor */ + if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin)) + { + Atom prop = MakeAtom("WM_STATE", strlen("WM_STATE"), True); + nxagentWMStateRec wmState; + wmState.state = 3; /* WithdrawnState */ + wmState.icon = None; + if (ChangeWindowProperty(pWin, prop, prop, 32, 0, 2, &wmState, 1) != Success) + fprintf(stderr, "nxagentUnRealizeWindow: Changing WM_STATE failed.\n"); + } + + XUnmapWindow(nxagentDisplay, nxagentWindow(pWin)); + + return True; +} + +void nxagentFrameBufferPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what) +{ + + void (*PaintWindowBackgroundBackup)(WindowPtr, RegionPtr, int); + + if (pWin->backgroundState == BackgroundPixmap) + { + pWin->background.pixmap = nxagentVirtualPixmap(pWin->background.pixmap); + } + + if (pWin->borderIsPixel == False) + { + pWin->border.pixmap = nxagentVirtualPixmap(pWin->border.pixmap); + } + + PaintWindowBackgroundBackup = pWin->drawable.pScreen -> PaintWindowBackground; + + pWin->drawable.pScreen -> PaintWindowBackground = nxagentFrameBufferPaintWindow; + + fbPaintWindow(pWin, pRegion, what); + + pWin->drawable.pScreen -> PaintWindowBackground = PaintWindowBackgroundBackup; + + if (pWin->backgroundState == BackgroundPixmap) + { + pWin->background.pixmap = nxagentRealPixmap(pWin->background.pixmap); + } + + if (pWin->borderIsPixel == False) + { + pWin->border.pixmap = nxagentRealPixmap(pWin->border.pixmap); + } +} + +void nxagentPaintWindowBackground(pWin, pRegion, what) + WindowPtr pWin; + RegionPtr pRegion; + int what; +{ + int i; + + RegionRec temp; + + if (pWin -> realized) + { + BoxPtr pBox; + + pBox = RegionRects(pRegion); + + for (i = 0; i < RegionNumRects(pRegion); i++) + { + XClearArea(nxagentDisplay, nxagentWindow(pWin), + pBox[i].x1 - pWin->drawable.x, + pBox[i].y1 - pWin->drawable.y, + pBox[i].x2 - pBox[i].x1, + pBox[i].y2 - pBox[i].y1, + False); + } + } + #ifdef TEST + else + { + fprintf(stderr, "nxagentPaintWindowBackground: Saving the operation with window " + "at [%p] not realized.\n", (void *) pWin); + } + #endif + + /* + * The framebuffer operations don't take care of + * clipping to the actual area of the framebuffer + * so we need to clip ourselves. + */ + + RegionInit(&temp, NullBox, 1); + + RegionIntersect(&temp, pRegion, &pWin -> clipList); + + nxagentFrameBufferPaintWindow(pWin, &temp, what); + + RegionUninit(&temp); +} + +void nxagentPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what) +{ + RegionRec temp; + + /* + * The framebuffer operations don't take care of + * clipping to the actual area of the framebuffer + * so we need to clip ourselves. + */ + + RegionInit(&temp, NullBox, 1); + + RegionIntersect(&temp, pRegion, &pWin -> borderClip); + + nxagentFrameBufferPaintWindow(pWin, &temp, what); + + RegionUninit(&temp); +} + +void nxagentCopyWindow(WindowPtr pWin, xPoint oldOrigin, RegionPtr oldRegion) +{ + fbCopyWindow(pWin, oldOrigin, oldRegion); +} + +void nxagentClipNotify(WindowPtr pWin, int dx, int dy) +{ + /* + * nxagentConfigureWindow(pWin, CWStackingOrder); + */ + + nxagentAddConfiguredWindow(pWin, CWStackingOrder); + nxagentAddConfiguredWindow(pWin, CW_Shape); + +#ifdef NXAGENT_SHAPE + return; +#else + +#ifdef SHAPE + +/* + * nxagentShapeWindow(pWin); + */ + +#endif /* SHAPE */ + +#endif /* NXAGENT_SHAPE */ +} + +void nxagentWindowExposures(WindowPtr pWin, RegionPtr pRgn, RegionPtr other_exposed) +{ + /* + * The problem: we want to synthetize the expose events internally, so + * that we reduce the time between a window operation and the corresp- + * onding graphical output, but at the same time we need to take care + * of the remote exposures, as we need to handle those cases where our + * windows are covered by the windows on the real display. Handling + * both the local and the remote exposures we would generate the same + * redraws twice, something we call "double refreshes", so we must be + * able to identify which events have been already sent to our clients. + * + * Here is how the algorithm is working: + * + * - We collect the exposures that the agent sent to its clients in a + * region (the "local-region") and store the region for a given win- + * dow in a vector. + * + * - Another region collects the expose that were received from the + * real X server (the "remote-region") for the same window. + * + * - We create a "fake" off-screen window. For every generated region + * we send a ConfigureWindow request for that window to synchronize + * ourselves with both the remote X server and/or the window manager. + * + * - When the ConfigureNotify is received, we calculate the difference + * between the "remote-region" and the "local-region" for the window + * that had collected exposures. + * + * - Finally we send the resulting exposures to our clients. + * + * As you may have guessed, the windows are synchronized per-region, + * that is there is a single region for a set of exposures. The regions + * are handled in order. This means that we can always calculate the + * final region by referring to the first element of the vector. + */ + + RegionRec temp; + BoxRec box; + + if (nxagentSessionState != SESSION_DOWN) + { + if (nxagentExposeArrayIsInitialized == 0) + { + int i; + + XSetWindowAttributes attributes; + + #ifdef TEST + fprintf(stderr, "nxagentWindowExposures: Initializing expose queue.\n"); + #endif + + attributes.event_mask = StructureNotifyMask; + + for (i = 0; i < EXPOSED_SIZE; i++) + { + nxagentExposeQueue.exposures[i].pWindow = NULL; + nxagentExposeQueue.exposures[i].localRegion = NullRegion; + nxagentExposeQueue.exposures[i].remoteRegion = NullRegion; + nxagentExposeQueue.exposures[i].remoteRegionIsCompleted = False; + nxagentExposeQueue.exposures[i].serial = 0; + } + + nxagentExposeQueue.length = 0; + + nxagentExposeSerial = 0; + + nxagentExposeQueue.start = 0; + + nxagentConfiguredSynchroWindow = XCreateWindow(nxagentDisplay, DefaultRootWindow(nxagentDisplay), 0, 0, + 1, 1, 0, 0, InputOutput, 0, CWEventMask, &attributes); + + nxagentInitRemoteExposeRegion(); + + nxagentExposeArrayIsInitialized = 1; + } + + RegionInit(&temp, (BoxRec *) NULL, 1); + + if (pRgn != NULL) + { + if (RegionNumRects(pRgn) > RECTLIMIT) + { + box = *RegionExtents(pRgn); + + RegionEmpty(pRgn); + RegionInit(pRgn, &box, 1); + } + + RegionUnion(&temp, &temp, pRgn); + } + + if (other_exposed != NULL) + { + RegionUnion(&temp, &temp, other_exposed); + } + + if (RegionNil(&temp) == 0) + { + RegionTranslate(&temp, + -(pWin -> drawable.x), -(pWin -> drawable.y)); + + if (nxagentExposeQueue.length < EXPOSED_SIZE) + { + int index; + + index = (nxagentExposeQueue.start + nxagentExposeQueue.length) % EXPOSED_SIZE; + + nxagentExposeQueue.exposures[index].pWindow = pWin; + + nxagentExposeQueue.exposures[index].localRegion = RegionCreate(NULL, 1); + + if (nxagentOption(Rootless) && nxagentWindowPriv(pWin) && + (nxagentWindowPriv(pWin) -> isMapped == 0 || + nxagentWindowPriv(pWin) -> visibilityState != VisibilityUnobscured)) + { + nxagentExposeQueue.exposures[index].remoteRegion = RegionCreate(NULL, 1); + + RegionUnion(nxagentExposeQueue.exposures[index].remoteRegion, + nxagentExposeQueue.exposures[index].remoteRegion, &temp); + + #ifdef TEST + fprintf(stderr, "nxagentWindowExposures: Added region to remoteRegion for window [%ld] to position [%d].\n", + nxagentWindow(pWin), nxagentExposeQueue.length); + #endif + } + else + { + RegionUnion(nxagentExposeQueue.exposures[index].localRegion, + nxagentExposeQueue.exposures[index].localRegion, &temp); + + #ifdef TEST + fprintf(stderr, "nxagentWindowExposures: Added region to localRegion for window [%ld] to position [%d].\n", + nxagentWindow(pWin), nxagentExposeQueue.length); + #endif + } + + nxagentExposeSerial = (nxagentExposeSerial - 1) % EXPOSED_SIZE; + + nxagentExposeQueue.exposures[index].serial = nxagentExposeSerial; + + #ifdef TEST + fprintf(stderr, "nxagentWindowExposures: Added region to queue with serial [%d].\n", nxagentExposeSerial); + #endif + + /* + * Mark this region for sending a synchro, + * in nxagentFlushConfigureWindow(). + */ + + nxagentExposeQueue.exposures[index].synchronize = 1; + + nxagentExposeQueue.length++; + + if (nxagentOption(Rootless) && nxagentWindowPriv(pWin) && + (nxagentWindowPriv(pWin) -> isMapped == 0 || + nxagentWindowPriv(pWin) -> visibilityState != VisibilityUnobscured)) + { + RegionUninit(&temp); + + return; + } + } + else + { + RegionUninit(&temp); + + #ifdef TEST + fprintf(stderr, "nxagentWindowExposures: WARNING! Reached maximum size of collect exposures vector.\n"); + #endif + + if ((pRgn != NULL && RegionNotEmpty(pRgn) != 0) || + (other_exposed != NULL && RegionNotEmpty(other_exposed) != 0)) + { + nxagentUnmarkExposedRegion(pWin, pRgn, other_exposed); + + miWindowExposures(pWin, pRgn, other_exposed); + } + + return; + } + } + + RegionUninit(&temp); + } + + if ((pRgn != NULL && RegionNotEmpty(pRgn) != 0) || + (other_exposed != NULL && RegionNotEmpty(other_exposed) != 0)) + { + nxagentUnmarkExposedRegion(pWin, pRgn, other_exposed); + + miWindowExposures(pWin, pRgn, other_exposed); + } + + return; +} + +#ifdef SHAPE +static Bool nxagentRegionEqual(RegionPtr pReg1, RegionPtr pReg2) +{ + BoxPtr pBox1, pBox2; + unsigned int n1, n2; + + if (pReg1 == pReg2) return True; + + if (pReg1 == NullRegion || pReg2 == NullRegion) return False; + + pBox1 = RegionRects(pReg1); + n1 = RegionNumRects(pReg1); + + pBox2 = RegionRects(pReg2); + n2 = RegionNumRects(pReg2); + + if (n1 != n2) return False; + + if (pBox1 == pBox2) return True; + + if (memcmp(pBox1, pBox2, n1 * sizeof(BoxRec))) return False; + + return True; +} + +void nxagentShapeWindow(WindowPtr pWin) +{ + Region reg; + BoxPtr pBox; + XRectangle rect; + int i; + + if (NXDisplayError(nxagentDisplay) == 1) + { + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentShapeWindow: Window at [%p][%ld].\n", + (void *) pWin, nxagentWindow(pWin)); + #endif + + if (!nxagentRegionEqual(nxagentWindowPriv(pWin)->boundingShape, + wBoundingShape(pWin))) + { + #ifdef DEBUG + fprintf(stderr, "nxagentShapeWindow: Bounding shape differs.\n"); + #endif + + if (wBoundingShape(pWin)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentShapeWindow: wBounding shape has [%ld] rects.\n", + RegionNumRects(wBoundingShape(pWin))); + #endif + +#ifdef NXAGENT_SHAPE2 + if (!nxagentWindowPriv(pWin)->boundingShape) + { + nxagentWindowPriv(pWin)->boundingShape = RegionCreate(NULL, 1); + } +#endif + + RegionCopy( + nxagentWindowPriv(pWin)->boundingShape, wBoundingShape(pWin)); + + reg = XCreateRegion(); + pBox = RegionRects(nxagentWindowPriv(pWin)->boundingShape); + for (i = 0; + i < RegionNumRects(nxagentWindowPriv(pWin)->boundingShape); + i++) + { + rect.x = pBox[i].x1; + rect.y = pBox[i].y1; + rect.width = pBox[i].x2 - pBox[i].x1; + rect.height = pBox[i].y2 - pBox[i].y1; + XUnionRectWithRegion(&rect, reg, reg); + } + +#ifndef NXAGENT_SHAPE + XShapeCombineRegion(nxagentDisplay, nxagentWindow(pWin), + ShapeBounding, 0, 0, reg, ShapeSet); +#endif + + XDestroyRegion(reg); + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentShapeWindow: wBounding shape does not exist. Removing the shape.\n"); + #endif + + RegionEmpty( + nxagentWindowPriv(pWin)->boundingShape); + +#ifndef NXAGENT_SHAPE + XShapeCombineMask(nxagentDisplay, nxagentWindow(pWin), + ShapeBounding, 0, 0, None, ShapeSet); +#endif + + } + } + + if (!nxagentRegionEqual(nxagentWindowPriv(pWin)->clipShape, wClipShape(pWin))) + { + #ifdef DEBUG + fprintf(stderr, "nxagentShapeWindow: Clip shape differs.\n"); + #endif + + if (wClipShape(pWin)) + { + #ifdef DEBUG + fprintf(stderr, "nxagentShapeWindow: wClip shape has [%ld] rects.\n", + RegionNumRects(wClipShape(pWin))); + #endif + +#ifdef NXAGENT_SHAPE2 + if (!nxagentWindowPriv(pWin)->clipShape) + { + nxagentWindowPriv(pWin)->clipShape = RegionCreate(NULL, 1); + } +#endif + + RegionCopy( + nxagentWindowPriv(pWin)->clipShape, wClipShape(pWin)); + + reg = XCreateRegion(); + pBox = RegionRects(nxagentWindowPriv(pWin)->clipShape); + for (i = 0; + i < RegionNumRects(nxagentWindowPriv(pWin)->clipShape); + i++) + { + rect.x = pBox[i].x1; + rect.y = pBox[i].y1; + rect.width = pBox[i].x2 - pBox[i].x1; + rect.height = pBox[i].y2 - pBox[i].y1; + XUnionRectWithRegion(&rect, reg, reg); + } + +#ifndef NXAGENT_SHAPE + XShapeCombineRegion(nxagentDisplay, nxagentWindow(pWin), + ShapeClip, 0, 0, reg, ShapeSet); +#endif + + XDestroyRegion(reg); + } + else + { + #ifdef DEBUG + fprintf(stderr, "nxagentShapeWindow: wClip shape does not exist. Removing the shape.\n"); + #endif + + RegionEmpty( + nxagentWindowPriv(pWin)->clipShape); + +#ifndef NXAGENT_SHAPE + XShapeCombineMask(nxagentDisplay, nxagentWindow(pWin), + ShapeClip, 0, 0, None, ShapeSet); +#endif + } + } +} +#endif /* SHAPE */ + +static int nxagentForceExposure(WindowPtr pWin, void * ptr) +{ + RegionPtr exposedRgn; + BoxRec Box; + WindowPtr pRoot = pWin->drawable.pScreen->root; + + if (pWin -> drawable.class != InputOnly) + { + Box.x1 = pWin->drawable.x; + Box.y1 = pWin->drawable.y; + Box.x2 = Box.x1 + pWin->drawable.width; + Box.y2 = Box.y1 + pWin->drawable.height; + + exposedRgn = RegionCreate(&Box, 1); + RegionIntersect(exposedRgn, exposedRgn, &pRoot->winSize); + + if (exposedRgn != NULL && RegionNotEmpty(exposedRgn) != 0) + { + miWindowExposures(pWin, exposedRgn, NullRegion); + } + + RegionDestroy(exposedRgn); + } + + return WT_WALKCHILDREN; +} + +void nxagentRefreshWindows(WindowPtr pWin) +{ + int action = 1; + + TraverseTree(pWin, nxagentForceExposure, &action); +} + +void nxagentUnmapWindows(void) +{ + int i; + + if (nxagentOption(Fullscreen) == 1) + { + for (i = 0; i < screenInfo.numScreens; i++) + { + if (nxagentDefaultWindows[i]) + { + XUnmapWindow(nxagentDisplay, nxagentDefaultWindows[i]); + } + } + } + + NXFlushDisplay(nxagentDisplay, NXFlushLink); +} + +void nxagentMapDefaultWindows() +{ + int i; + + for (i = 0; i < screenInfo.numScreens; i++) + { + WindowPtr pWin = screenInfo.screens[i]->root; + + ScreenPtr pScreen = pWin -> drawable.pScreen; + + MapWindow(pWin, serverClient); + + if (nxagentOption(Rootless) == 0) + { + /* + * Show the NX splash screen. + */ + + #ifdef TEST + fprintf(stderr, "nxagentMapDefaultWindows: Showing the splash window.\n"); + #endif + + nxagentShowSplashWindow(nxagentDefaultWindows[pScreen->myNum]); + + /* + * Map the default window. Defer the mapping if the session is + * of shadow type. If no WM is running on the remote display, + * map the window soon anyway: this avoids a flickering effect + * on the !M logo if the shadow session is displayed from a + * Windows client. + */ + + if (nxagentOption(Shadow) == 0 || nxagentWMIsRunning == 0) + { + #ifdef TEST + fprintf(stderr, "nxagentMapDefaultWindows: Mapping default window id [%ld].\n", + nxagentDefaultWindows[pScreen->myNum]); + #endif + + XMapWindow(nxagentDisplay, nxagentDefaultWindows[pScreen->myNum]); + + if (nxagentOption(Fullscreen) == 1 && nxagentWMIsRunning == 1) + { + nxagentMaximizeToFullScreen(pScreen); + } + } + + /* + * Map and raise the input window. + */ + + XMapWindow(nxagentDisplay, nxagentInputWindows[pScreen->myNum]); + + /* + * At reconnection the Input Window is + * raised in nxagentReconnectAllWindows, + * after the Root Window is mapped. + */ + + if (nxagentReconnectTrap == 0) + { + XRaiseWindow(nxagentDisplay, nxagentInputWindows[pScreen->myNum]); + } + } + + /* + * Send a SetSelectionOwner request + * to notify of the agent start. + */ + + XSetSelectionOwner(nxagentDisplay, serverCutProperty, + nxagentDefaultWindows[i], CurrentTime); + } + + /* + * Map the icon window. + */ + + if (nxagentIconWindow != 0) + { + #ifdef TEST + fprintf(stderr, "nxagentMapDefaultWindows: Mapping icon window id [%ld].\n", + nxagentIconWindow); + #endif + + XMapWindow(nxagentDisplay, nxagentIconWindow); + + if (nxagentIpaq != 0) + { + XIconifyWindow(nxagentDisplay, nxagentIconWindow, + DefaultScreen(nxagentDisplay)); + } + } + + /* + * Ensure that the fullscreen window gets the focus. + */ + + if (nxagentFullscreenWindow != 0) + { + XSetInputFocus(nxagentDisplay, nxagentFullscreenWindow, + RevertToParent, CurrentTime); + } + + #ifdef TEST + fprintf(stderr, "nxagentMapDefaultWindows: Completed mapping of default windows.\n"); + #endif +} + +Bool nxagentDisconnectAllWindows(void) +{ + Bool succeded = True; + int i; + WindowPtr pWin; + + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_WINDOW_DEBUG) + fprintf(stderr, "nxagentDisconnectAllWindows\n"); + #endif + + for (i = 0; i < screenInfo.numScreens; i++) + { + pWin = screenInfo.screens[i]->root; + nxagentTraverseWindow( pWin, nxagentDisconnectWindow, &succeded); + nxagentDefaultWindows[i] = None; + } + + #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG + fprintf(stderr, "nxagentDisconnectAllWindows: all windows disconnected\n"); + #endif + + return succeded; +} + +/* + * FIXME: We are giving up reconnecting those void * + * that are not resource, and we are just disconnecting them. + * perhaps we could do better and reconnect them. + */ + +void nxagentDisconnectWindow(void * p0, XID x1, void * p2) +{ + WindowPtr pWin = (WindowPtr)p0; + Bool* pBool = (Bool*)p2; + CursorPtr pCursor = wCursor(pWin); + ScreenPtr pScreen = pWin -> drawable.pScreen; + + if ((pCursor = wCursor(pWin)) && + nxagentCursorPriv(pCursor, pScreen) && + nxagentCursor(pCursor, pScreen)) + { + #ifdef NXAGENT_RECONNECT_CURSOR_DEBUG_disabled + char msg[] = "nxagentDisconnectWindow:"; + + nxagentPrintCursorInfo(pCursor, msg); + #endif + + #ifdef NXAGENT_RECONNECT_CURSOR_DEBUG + fprintf(stderr, "nxagentDisconnectWindow: window %p - disconnecting cursor %p ID %lx\n", + pWin, pCursor, nxagentCursor(pCursor, pScreen)); + #endif + + nxagentDisconnectCursor(pCursor, (XID)0, pBool); + + if (*pBool == False) + { + #ifdef WARNING + fprintf(stderr, "nxagentDisconnectWindow: WARNING failed disconnection of cursor at [%p]" + " for window at [%p]: ignoring it.\n", (void*)pCursor, (void*)pWin); + #endif + + *pBool = True; + } + } + #ifdef NXAGENT_RECONNECT_CURSOR_DEBUG + else if (pCursor) + { + fprintf(stderr, "nxagentDisconnectWindow: window %p - cursor %p already disconnected\n", + pWin, pCursor); + } + #endif + + nxagentWindow(pWin) = None; + + if (nxagentDrawableStatus((DrawablePtr) pWin) == NotSynchronized) + { + nxagentDestroyCorruptedResource((DrawablePtr) pWin, RT_NX_CORR_WINDOW); + } +} + +Bool nxagentReconnectAllWindows(void *p0) +{ + int flexibility = *(int *) p0; + + flexibility = flexibility; + + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_WINDOW_DEBUG) + fprintf(stderr, "nxagentReconnectAllWindows\n"); + #endif + + if (screenInfo.screens[0]->root -> backgroundState == BackgroundPixmap && + screenInfo.screens[0]->root -> background.pixmap == NULL) + { + FatalError("nxagentReconnectAllWindows: correct the FIXME\n"); + } + + if (nxagentOption(Fullscreen)) + { + screenInfo.screens[0]->root -> origin.x = nxagentOption(RootX); + screenInfo.screens[0]->root -> origin.y = nxagentOption(RootY); + } + + if (!nxagentLoopOverWindows(nxagentReconnectWindow)) + { + #ifdef WARNING + fprintf(stderr, "nxagentReconnectAllWindows: couldn't recreate windows\n"); + #endif + + return False; + } + + #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG + XSync(nxagentDisplay, 0); + fprintf(stderr, "nxagentReconnectAllWindows: all windows recreated\n"); + #endif + + if (!nxagentLoopOverWindows(nxagentReconfigureWindow)) + { + #ifdef WARNING + fprintf(stderr, "nxagentReconnectAllWindows: couldn't reconfigure windows\n"); + #endif + + return False; + } + + /* + * After the Root Window has + * been mapped, the Input + * Windows is raised. + */ + + if (nxagentOption(Rootless) == 0) + { + int i; + + for (i = 0; i < screenInfo.numScreens; i++) + { + XRaiseWindow(nxagentDisplay, nxagentInputWindows[i]); + } + } + + nxagentFlushConfigureWindow(); + + if (nxagentOption(Fullscreen)) + { + screenInfo.screens[0]->root -> origin.x = 0; + screenInfo.screens[0]->root -> origin.y = 0; + } + + #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG + + XSync(nxagentDisplay, 0); + + fprintf(stderr, "nxagentReconnectAllWindows: All windows reconfigured.\n"); + + #endif + + if (nxagentInitClipboard(screenInfo.screens[0]->root) == -1) + { + #ifdef WARNING + fprintf(stderr, "nxagentReconnectAllWindows: WARNING! Couldn't initialize the clipboard.\n"); + #endif + + return False; + } + + #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG + + XSync(nxagentDisplay, 0); + + fprintf(stderr, "nxagentReconnectAllWindows: Clipboard initialized.\n"); + + #endif + + #ifdef VIEWPORT_FRAME + + /* + * We move the viewport frames out of the way on the X server side. + */ + + if (nxagentViewportFrameLeft && + nxagentViewportFrameRight && + nxagentViewportFrameAbove && + nxagentViewportFrameBelow) + { + XMoveWindow(nxagentDisplay, nxagentWindow(nxagentViewportFrameLeft), + -NXAGENT_FRAME_WIDTH, 0); + XMoveWindow(nxagentDisplay, nxagentWindow(nxagentViewportFrameRight), + nxagentOption(RootWidth), 0); + XMoveWindow(nxagentDisplay, nxagentWindow(nxagentViewportFrameAbove), + 0, -NXAGENT_FRAME_WIDTH); + XMoveWindow(nxagentDisplay, nxagentWindow(nxagentViewportFrameBelow), + 0, nxagentOption(RootHeight)); + } + + #endif /* #ifdef VIEWPORT_FRAME */ + + return True; +} + +Bool nxagentSetWindowCursors(void *p0) +{ + int flexibility = *(int *) p0; + + flexibility = flexibility; + + #if defined(NXAGENT_RECONNECT_DEBUG) || defined(NXAGENT_RECONNECT_WINDOW_DEBUG) + fprintf(stderr, "nxagentSetWindowCursors: Going to loop over the windows.\n"); + #endif + + if (!nxagentLoopOverWindows(nxagentReconfigureWindowCursor)) + { + #ifdef WARNING + fprintf(stderr, "nxagentSetWindowCursors: WARNING! Couldn't configure all windows' cursors.\n"); + #endif + + return False; + } + + #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG + fprintf(stderr, "nxagentLoopOverWindows: All cursors configured.\n"); + #endif + + nxagentReDisplayCurrentCursor(); + + return True; +} + +static void nxagentTraverseWindow( + WindowPtr pWin, + void (*pF)(void *, XID, void *), + void * p) +{ + pF(pWin, 0, p); + + if (pWin -> nextSib) + { + nxagentTraverseWindow(pWin -> nextSib, pF, p); + } + + if (pWin -> firstChild) + { + nxagentTraverseWindow(pWin -> firstChild, pF, p); + } +} + +static Bool nxagentLoopOverWindows(void (*pF)(void *, XID, void *)) +{ + int i; + Bool windowSuccess = True; + WindowPtr pWin; + + for (i = 0; i < screenInfo.numScreens; i++) + { + pWin = screenInfo.screens[i]->root; + nxagentTraverseWindow(pWin, pF, &windowSuccess); + } + + return windowSuccess; +} + +static void nxagentReconnectWindow(void * param0, XID param1, void * data_buffer) +{ + WindowPtr pWin = (WindowPtr)param0; + Bool *pBool = (Bool*)data_buffer; + Visual *visual; + unsigned long mask; + XSetWindowAttributes attributes; + ColormapPtr pCmap; + + if (!pWin || !*pBool) + return; + + #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG + fprintf(stderr, "nxagentReconnectWindow: %p - ID %lx\n", pWin, nxagentWindow(pWin)); + #endif + + if (pWin->drawable.class == InputOnly) { + mask = CWEventMask; + visual = CopyFromParent; + } + else { + mask = CWEventMask | CWBackingStore; + + attributes.backing_store = NotUseful; + + if (pWin->optional) + { + mask |= CWBackingPlanes | CWBackingPixel; + attributes.backing_planes = pWin->optional->backingBitPlanes; + attributes.backing_pixel = pWin->optional->backingPixel; + } + +/* +FIXME: Do we need to set save unders attribute here? +*/ + if (nxagentSaveUnder == True) + { + mask |= CWSaveUnder; + attributes.save_under = pWin->saveUnder; + } + + if (pWin->parent) { + if (pWin->optional && pWin->optional->visual != wVisual(pWin->parent)) { + visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin)); + mask |= CWColormap; + if (pWin->optional->colormap) { + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP); + attributes.colormap = nxagentColormap(pCmap); + } + else + attributes.colormap = nxagentDefaultVisualColormap(visual); + } + else + visual = CopyFromParent; + } + else { /* root windows have their own colormaps at creation time */ + visual = nxagentVisualFromID(pWin->drawable.pScreen, wVisual(pWin)); + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWin), RT_COLORMAP); + mask |= CWColormap; + attributes.colormap = nxagentColormap(pCmap); + } + } + + if (mask & CWEventMask) + { + /* Assume that the mask fits in int... broken on Big Endian 64bit systems. */ + Mask tmp_mask = attributes.event_mask; + nxagentGetEventMask(pWin, &tmp_mask); + attributes.event_mask = (int)tmp_mask; + } + #ifdef WARNING + else + { + attributes.event_mask = NoEventMask; + } + #endif + + #ifdef TEST + fprintf(stderr, "nxagentReconnectWindow: Going to create new window.\n"); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentReconnectWindow: Recreating %swindow at %p current event mask = %lX mask & CWEventMask = %ld " + "event_mask = %lX\n", + nxagentWindowTopLevel(pWin) ? "toplevel " : "", (void*)pWin, pWin -> eventMask, + mask & CWEventMask, attributes.event_mask); + #endif + + /* + * FIXME: This quick hack is intended to solve a + * problem of NXWin X server for windows. + * The NXWin minimize the windows moving them + * out of the screen area, this behaviour + * can cause problem when a rootless session + * is disconnected and an apps is minimized. + * It will be solved with new Xorg version of + * the NXWin server. + */ + + if (nxagentOption(Rootless)) + { + if (pWin -> drawable.x == -32000 && pWin -> drawable.y == -32000) + { + pWin -> drawable.x = (pWin -> drawable.pScreen -> width - pWin -> drawable.width) / 2; + pWin -> drawable.y = (pWin -> drawable.pScreen -> height - pWin -> drawable.height) /2; + } + + if (pWin -> origin.x == -32000 && pWin -> origin.y == -32000) + { + pWin -> origin.x = (pWin -> drawable.pScreen -> width - pWin -> drawable.width) / 2; + pWin -> origin.y = (pWin -> drawable.pScreen -> height - pWin -> drawable.height) / 2; + } + } + + nxagentWindow(pWin) = XCreateWindow(nxagentDisplay, + nxagentWindowParent(pWin), + pWin->origin.x - + wBorderWidth(pWin), + pWin->origin.y - + wBorderWidth(pWin), + pWin->drawable.width, + pWin->drawable.height, + pWin->borderWidth, + pWin->drawable.depth, + pWin->drawable.class, + visual, + mask, + &attributes); + + #ifdef TEST + fprintf(stderr, "nxagentReconnectWindow: Created new window with id [%ld].\n", + nxagentWindowPriv(pWin)->window); + #endif + + /* + * We have to set the WM_DELETE_WINDOW protocols + * on every top level window, because we don't know + * if a client handles this. + */ + + if (nxagentOption(Rootless) && (pWin != screenInfo.screens[0]->root)) + { + if (nxagentWindowTopLevel(pWin)) + { + Atom prop = nxagentMakeAtom("WM_PROTOCOLS", strlen("WM_PROTOCOLS"), True); + + XlibAtom atom = nxagentMakeAtom("WM_DELETE_WINDOW", strlen("WM_DELETE_WINDOW"), True); + + XSetWMProtocols(nxagentDisplay, nxagentWindow(pWin), &atom, 1); + + nxagentAddPropertyToList(prop, pWin); + } + + nxagentExportAllProperty(pWin); + + if (nxagentWindowTopLevel(pWin)) + { + int ret; + Atom type; + int format; + unsigned long nItems, bytesLeft; + XSizeHints *props, hints; + unsigned char *data = NULL; + + #ifdef _XSERVER64 + + unsigned char *data64 = NULL; + unsigned int i; + + #endif + + hints.flags = 0; + + ret = GetWindowProperty(pWin, + XA_WM_NORMAL_HINTS, + 0, sizeof(XSizeHints), + False, XA_WM_SIZE_HINTS, + &type, &format, &nItems, &bytesLeft, &data); + + /* + * 72 is the number of bytes returned by + * sizeof(XSizeHints) on 32 bit platforms. + */ + + if (ret == Success && + ((format >> 3) * nItems) == 72 && + bytesLeft == 0 && + type == XA_WM_SIZE_HINTS) + { + #ifdef TEST + fprintf(stderr, "nxagentReconnectWindow: setting WMSizeHints on window %p [%lx - %lx].\n", + (void*)pWin, pWin -> drawable.id, nxagentWindow(pWin)); + #endif + + #ifdef _XSERVER64 + + data64 = (unsigned char *) malloc(sizeof(XSizeHints) + 4); + + for (i = 0; i < 4; i++) + { + *(data64 + i) = *(data + i); + } + + *(((int *) data64) + 1) = 0; + + for (i = 8; i < sizeof(XSizeHints) + 4; i++) + { + *(data64 + i) = *(data + i - 4); + } + + props = (XSizeHints *) data64; + + #else + + props = (XSizeHints *) data; + + #endif /* _XSERVER64 */ + + hints = *props; + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentReconnectWindow: Failed to get property WM_NORMAL_HINTS on window %p\n", + (void*)pWin); + #endif + } + + hints.flags |= (USPosition | PWinGravity); + hints.x = pWin -> drawable.x; + hints.y = pWin -> drawable.y; + hints.win_gravity = StaticGravity; + + XSetWMNormalHints(nxagentDisplay, + nxagentWindow(pWin), + &hints); + + #ifdef _XSERVER64 + + if (data64 != NULL) + { + free(data64); + } + + #endif + } + } + + if (nxagentDrawableStatus((DrawablePtr) pWin) == NotSynchronized) + { + nxagentAllocateCorruptedResource((DrawablePtr) pWin, RT_NX_CORR_WINDOW); + } +} + +static void nxagentReconfigureWindowCursor(void * param0, XID param1, void * data_buffer) +{ + WindowPtr pWin = (WindowPtr)param0; + Bool *pBool = (Bool*)data_buffer; + CursorPtr pCursor; + ScreenPtr pScreen; + + if (!pWin || !*pBool || !(pCursor = wCursor(pWin))) + return; + + pScreen = pWin -> drawable.pScreen; + + if (!(nxagentCursorPriv(pCursor, pScreen))) + { + return; + } + + #ifdef DEBUG + fprintf(stderr, "nxagentReconfigureWindowCursor: %p - ID %lx geometry (%d,%d,%d,%d) " + "cursor %p - ID %lx\n", + pWin, nxagentWindow(pWin), + pWin -> drawable.x, + pWin -> drawable.y, + pWin -> drawable.width, + pWin -> drawable.height, + pCursor, nxagentCursor(pCursor, pScreen)); + #endif + + if (nxagentCursor(pCursor, pScreen) == None) + { + #ifdef NXAGENT_RECONNECT_WINDOW_DEBUG + fprintf(stderr, "nxagentReconfigureWindowCursor: reconnecting valid cursor %lx\n", + (void*)pCursor); + #endif + + nxagentReconnectCursor(pCursor, 0, pBool); + + if (!*pBool) + { + #ifdef WARNING + fprintf(stderr, "nxagentReconfigureWindowCursor: WARNING " + "failed reconnection of cursor at [%p] for window at [%p]: ignoring it.\n", + (void*)pCursor, (void*)pWin); + #endif + + *pBool = True; + } + } + + if (nxagentOption(Rootless)) + { + XDefineCursor(nxagentDisplay,nxagentWindow(pWin),nxagentCursor(pCursor,pScreen)); + } +} + +static void nxagentReconfigureWindow(void * param0, XID param1, void * data_buffer) +{ + WindowPtr pWin = (WindowPtr)param0; + unsigned long mask = 0; + + #ifdef DEBUG + fprintf(stderr, "nxagentReconfigureWindow: pWin %p - ID %lx\n", pWin, nxagentWindow(pWin)); + #endif + + if (pWin -> drawable.class == InputOnly) + mask = CWWinGravity | CWEventMask | CWDontPropagate | CWOverrideRedirect | CWCursor; + else + mask = CWBackPixmap | CWBackPixel | CWBorderPixmap | CWBorderPixel | + CWBitGravity | CWWinGravity | CWBackingStore | CWBackingPlanes | + CWBackingPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask | + CWDontPropagate | CWColormap | CWCursor; + + nxagentChangeWindowAttributes(pWin, mask); + +#ifdef SHAPE + if (nxagentWindowPriv(pWin) -> boundingShape) + { + RegionDestroy( + nxagentWindowPriv(pWin) -> boundingShape); + nxagentWindowPriv(pWin) -> boundingShape = NULL; + } + + if (nxagentWindowPriv(pWin) -> clipShape) + { + RegionDestroy( + nxagentWindowPriv(pWin) -> clipShape); + nxagentWindowPriv(pWin) -> clipShape = NULL; + } + nxagentShapeWindow(pWin); +#endif + + if (pWin != screenInfo.screens[0]->root) + { + if (pWin->realized) + { + nxagentRealizeWindow (pWin); + } +/* +XXX: This would break Motif menus. + If pWin is mapped but not realized, a followin UnmapWindow() wouldn't + do anything, leaving this mapped window around. XMapWindow() + is called in nxagentRealizeWindow() and there it is enough. + + else if (pWin->mapped) + { + XMapWindow(nxagentDisplay, nxagentWindow(pWin)); + } +*/ + else if (nxagentOption(Rootless) && pWin -> overrideRedirect == 0 && + nxagentWindowTopLevel(pWin) && nxagentIsIconic(pWin)) + { + MapWindow(pWin, serverClient); + XIconifyWindow(nxagentDisplay, nxagentWindow(pWin), pWin -> drawable.pScreen -> myNum); + } + } + else if (nxagentOption(Rootless) == 0) + { + /* + * Map the root window. + */ + + XMoveWindow(nxagentDisplay, nxagentWindow(pWin), + nxagentOption(RootX), nxagentOption(RootY)); + + XMapWindow(nxagentDisplay, nxagentWindow(pWin)); + } +} + +Bool nxagentCheckIllegalRootMonitoring(WindowPtr pWin, Mask mask) +{ + Mask invalidMask = SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask; + + if (nxagentOption(Rootless) && + pWin == screenInfo.screens[0]->root && + (mask & invalidMask)) + { + return True; + } + + return False; +} + +#ifdef TEST + +Bool nxagentCheckWindowIntegrity(WindowPtr pWin) +{ + Bool integrity = True; + XImage *image; + char *data; + int format; + unsigned long plane_mask = AllPlanes; + unsigned int width, height, length, depth; + + width = pWin -> drawable.width; + height = pWin -> drawable.height; + depth = pWin -> drawable.depth; + format = (depth == 1) ? XYPixmap : ZPixmap; + + if (width && height) + { + length = nxagentImageLength(width, height, format, 0, depth); + data = malloc(length); + + if (data == NULL) + { + FatalError("nxagentCheckWindowIntegrity: Failed to allocate a buffer of size %d.\n", length); + } + + memset(data, 0, length); + + image = XGetImage(nxagentDisplay, nxagentWindow(pWin), 0, 0, + width, height, plane_mask, format); + if (image == NULL) + { + fprintf(stderr, "XGetImage: Failed.\n"); + return False; + } + + fbGetImage((DrawablePtr)pWin, 0, 0, width, height, format, plane_mask, data); + + if (image && memcmp(image->data, data, length) != 0) + { + #ifdef TEST + int i; + char *p, *q; + #endif + + integrity = False; + + #ifdef TEST + for (i = 0, p = image->data, q = data; i < length; i++) + { + if (p[i] != q[i]) + { + fprintf(stderr, "[%d] %d - %d !!!!!!!!!!!!!!!!!!! **************** !!!!!!!!!!!!!!!!!\n", i, p[i], q[i]); + } + else + { + fprintf(stderr, "[%d] %d - %d\n", i, p[i], q[i]); + } + } + #endif + + #ifdef WARNING + fprintf(stderr, "nxagentCheckWindowIntegrity: Window %p width %d, height %d, has been realized " + "but the data buffer still differs.\n", (void*) pWin, width, height); + fprintf(stderr, "nxagentCheckWindowIntegrity: bytes_per_line = %d byte pad %d format %d.\n", + image -> bytes_per_line, nxagentImagePad(width, height, 0, depth), image->format); + + fprintf(stderr, "nxagentCheckWindowIntegrity: image is corrupted!!\n"); + #endif + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckWindowIntegrity: Window %p has been realized " + "now remote and frambuffer data are synchronized.\n", (void*) pWin); + #endif + } + + if (image) + { + XDestroyImage(image); + } + + if (data) + { + free(data); + } + } + else + { + #ifdef WARNING + fprintf(stderr, "nxagentCheckWindowIntegrity: ignored window %p with geometry (%d,%d).\n", + (void*) pWin, width, height); + #endif + } + + return integrity; +} + +#endif + +Bool nxagentIsIconic(WindowPtr pWin) +{ + int iReturn; + unsigned long ulReturnItems; + unsigned long ulReturnBytesLeft; + Atom atomReturnType; + int iReturnFormat; + unsigned char *pszReturnData = NULL; + + if (!wUserProps (pWin)) + { + return 0; + } + + iReturn = GetWindowProperty(pWin, MakeAtom("WM_STATE", 8, False), 0, sizeof(CARD32), False, + AnyPropertyType, &atomReturnType, &iReturnFormat, + &ulReturnItems, &ulReturnBytesLeft, &pszReturnData); + + if (iReturn == Success) + { + return (((CARD32 *)pszReturnData)[0] == IconicState); + } + else + { + return 0; + } +} + +void nxagentSetTopLevelEventMask(pWin) + WindowPtr pWin; +{ + unsigned long mask = CWEventMask; + XSetWindowAttributes attributes; + + if (nxagentOption(Rootless) && nxagentWindowTopLevel(pWin)) + { + /* Assume that the mask fits in int... broken on Big Endian 64bit systems. */ + Mask tmp_mask = attributes.event_mask = NoEventMask; + nxagentGetEventMask(pWin, &tmp_mask); + attributes.event_mask = (int)tmp_mask; + + XChangeWindowAttributes(nxagentDisplay, nxagentWindow(pWin), mask, &attributes); + } +} + +/* + * This function must return 1 if we want the + * exposures to be sent as the window's extents. + * This is actually a harmless, but useful hack, + * as it speeds up the window redraws considera- + * bly, when using a very popular WM theme. + */ + +int nxagentExtentsPredicate(int total) +{ + #ifdef TEST + + if (total == 6 || total == 11 || total == 10) + { + fprintf(stderr, "nxagentExtentsPredicate: WARNING! Returning [%d] with [%d] rectangles.\n", + (total == 6 || total == 11 || total == 10), total); + } + + #endif + + return (total == 6 || total == 11 || total == 10); +} + +void nxagentFlushConfigureWindow(void) +{ + ConfiguredWindowStruct *index; + XWindowChanges changes; + int i; + int j; + + index = nxagentConfiguredWindowList; + + while (index) + { + if (index -> next == NULL) + { + break; + } + + index = index -> next; + } + + while (index) + { + ConfiguredWindowStruct *tmp; + + WindowPtr pWin = index -> pWin; + unsigned int valuemask = index -> valuemask; + + if (pWin && valuemask) + { + nxagentConfigureWindow(pWin, valuemask); + } + + tmp = index; + + if (index == nxagentConfiguredWindowList) + { + free(tmp); + break; + } + + index = index -> prev; + free(tmp); + } + + nxagentConfiguredWindowList = NULL; + + for (j = 0; j < nxagentExposeQueue.length; j++) + { + i = (nxagentExposeQueue.start + j) % EXPOSED_SIZE; + + if (nxagentExposeQueue.exposures[i].synchronize == 1) + { + changes.x = nxagentExposeQueue.exposures[i].serial; + changes.y = -2; + + #ifdef DEBUG + fprintf(stderr, "nxagentFlushConfigureWindow: Sending synch ConfigureWindow for " + "index [%d] serial [%d].\n", i, nxagentExposeQueue.exposures[i].serial); + #endif + + XConfigureWindow(nxagentDisplay, nxagentConfiguredSynchroWindow, + CWX | CWY, &changes); + + nxagentExposeQueue.exposures[i].synchronize = 0; + } + } + + nxagentSendDeferredBackgroundExposures(); + + return; +} + +void nxagentPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ +/* +FIXME: Do we need this here? + + nxagentFlushConfigureWindow(); +*/ + + return; +} + +void nxagentAddConfiguredWindow(WindowPtr pWin, unsigned int valuemask) +{ + unsigned int mask; + + mask = valuemask & (CWParent | CWX | CWY | CWWidth | CWHeight | + CWBorderWidth | CWStackingOrder | CW_Map | CW_Update | CW_Shape); + + valuemask &= ~(CWParent | CWX | CWY | CWWidth | CWHeight | CWBorderWidth | CWStackingOrder); + + if (mask & CWX && + nxagentWindowPriv(pWin)->x != + pWin->origin.x - wBorderWidth(pWin)) + { + valuemask |= CWX; + } + + if (mask & CWY && + nxagentWindowPriv(pWin)->y != + pWin->origin.y - wBorderWidth(pWin)) + { + valuemask |= CWY; + } + + if (mask & CWWidth && + nxagentWindowPriv(pWin)->width != + pWin->drawable.width) + { + valuemask |= CWWidth; + } + + if (mask & CWHeight && + nxagentWindowPriv(pWin)->height != + pWin->drawable.height) + { + valuemask |= CWHeight; + } + + if (mask & CWBorderWidth && + nxagentWindowPriv(pWin)->borderWidth != + pWin->borderWidth) + { + valuemask |= CWBorderWidth; + } + + if (mask & CWStackingOrder && + nxagentWindowPriv(pWin)->siblingAbove != + nxagentWindowSiblingAbove(pWin)) + { + valuemask |= CWStackingOrder; + } + + if (nxagentConfiguredWindowList == NULL) + { + nxagentConfiguredWindowList = malloc(sizeof(ConfiguredWindowStruct)); + nxagentConfiguredWindowList -> next = NULL; + nxagentConfiguredWindowList -> prev = NULL; + + nxagentConfiguredWindowList -> pWin = pWin; + } + else + { + ConfiguredWindowStruct *tmp; + + tmp = malloc(sizeof(ConfiguredWindowStruct)); + + tmp -> next = nxagentConfiguredWindowList; + nxagentConfiguredWindowList -> prev = tmp; + tmp -> prev = NULL; + nxagentConfiguredWindowList = tmp; + nxagentConfiguredWindowList -> pWin = pWin; + } + + nxagentConfiguredWindowList -> valuemask = valuemask; + + return; +} + +void nxagentDeleteConfiguredWindow(WindowPtr pWin) +{ + ConfiguredWindowStruct *index, *previous, *tmp; + + index = nxagentConfiguredWindowList; + + while (index) + { + WindowPtr pDel = index -> pWin; + + if (pDel == pWin) + { + if (index -> prev == NULL && index -> next == NULL) + { + free(nxagentConfiguredWindowList); + nxagentConfiguredWindowList = NULL; + + return; + } + else if (index -> prev == NULL) + { + tmp = nxagentConfiguredWindowList; + index = nxagentConfiguredWindowList = tmp -> next; + free(tmp); + nxagentConfiguredWindowList -> prev = NULL; + + continue; + } + else if (index -> next == NULL) + { + tmp = index; + index = index -> prev; + free(tmp); + index -> next = NULL; + + return; + } + + previous = index -> prev; + tmp = index; + index = index -> next; + previous -> next = index; + index -> prev = previous; + free(tmp); + + continue; + } + + index = index -> next; + } + + return; +} + +void nxagentAddStaticResizedWindow(WindowPtr pWin, unsigned long sequence, int offX, int offY) +{ + if (nxagentStaticResizedWindowList == NULL) + { + nxagentStaticResizedWindowList = malloc(sizeof(StaticResizedWindowStruct)); + nxagentStaticResizedWindowList -> next = NULL; + nxagentStaticResizedWindowList -> prev = NULL; + } + else + { + StaticResizedWindowStruct *tmp; + + tmp = malloc(sizeof(StaticResizedWindowStruct)); + + tmp -> next = nxagentStaticResizedWindowList; + nxagentStaticResizedWindowList -> prev = tmp; + tmp -> prev = NULL; + nxagentStaticResizedWindowList = tmp; + } + + nxagentStaticResizedWindowList -> pWin = pWin; + nxagentStaticResizedWindowList -> sequence = sequence; + nxagentStaticResizedWindowList -> offX = offX; + nxagentStaticResizedWindowList -> offY = offY; +} + +void nxagentDeleteStaticResizedWindow(unsigned long sequence) +{ + StaticResizedWindowStruct *index, *previous, *tmp; + + index = nxagentStaticResizedWindowList; + + while (index) + { + if (index -> sequence <= sequence) + { + if (index -> prev == NULL && index -> next == NULL) + { + free(nxagentStaticResizedWindowList); + nxagentStaticResizedWindowList = NULL; + + return; + } + else if (index -> prev == NULL) + { + tmp = nxagentStaticResizedWindowList; + index = nxagentStaticResizedWindowList = tmp -> next; + free(tmp); + nxagentStaticResizedWindowList -> prev = NULL; + + continue; + } + else if (index -> next == NULL) + { + tmp = index; + index = index -> prev; + free(tmp); + index -> next = NULL; + + return; + } + + previous = index -> prev; + tmp = index; + index = index -> next; + previous -> next = index; + index -> prev = previous; + free(tmp); + + continue; + } + + index = index -> next; + } + + return; +} + +StaticResizedWindowStruct *nxagentFindStaticResizedWindow(unsigned long sequence) +{ + StaticResizedWindowStruct *index; + StaticResizedWindowStruct *ret = NULL; + + if (nxagentStaticResizedWindowList == NULL) + { + return NULL; + } + + index = nxagentStaticResizedWindowList; + + while (index && index -> sequence > sequence) + { + ret = index; + index = index -> next; + } + + return ret; +} + +void nxagentEmptyBackingStoreRegion(void * param0, XID param1, void * data_buffer) +{ + WindowPtr pWin = (WindowPtr) param0; + + miBSWindowPtr pBackingStore = (miBSWindowPtr)pWin->backStorage; + + if (pBackingStore != NULL) + { + RegionEmpty(&pBackingStore->SavedRegion); + + #ifdef TEST + fprintf(stderr, "nxagentEmptyBackingStoreRegion: Emptying saved region for window at [%p].\n", (void*) pWin); + #endif + + if (pBackingStore -> pBackingPixmap != NULL) + { + #ifdef TEST + fprintf(stderr, "nxagentEmptyBackingStoreRegion: Emptying corrupted region for drawable at [%p].\n", + (void*) pBackingStore -> pBackingPixmap); + #endif + + nxagentUnmarkCorruptedRegion((DrawablePtr) pBackingStore -> pBackingPixmap, NullRegion); + } + } +} + +void nxagentEmptyAllBackingStoreRegions(void) +{ + if (nxagentLoopOverWindows(nxagentEmptyBackingStoreRegion) == 0) + { + #ifdef WARNING + fprintf(stderr, "nxagentEmptyAllSavedRegions: Failed to empty backing store saved regions.\n"); + #endif + } +} + +void nxagentInitBSPixmapList(void) +{ + memset(nxagentBSPixmapList, 0, BSPIXMAPLIMIT * sizeof( StoringPixmapPtr)); +} + +int nxagentAddItemBSPixmapList(unsigned long id, PixmapPtr pPixmap, WindowPtr pWin, int bsx, int bsy) +{ + int i; + + for (i = 0; i < BSPIXMAPLIMIT; i++) + { + if (nxagentBSPixmapList[i] == NULL) + { + nxagentBSPixmapList[i] = malloc(sizeof(StoringPixmapRec)); + + if (nxagentBSPixmapList[i] == NULL) + { + FatalError("nxagentAddItemBSPixmapList: Failed to allocate memory for nxagentBSPixmapList.\n"); + } + + nxagentBSPixmapList[i] -> storingPixmapId = id; + nxagentBSPixmapList[i] -> pStoringPixmap = pPixmap; + nxagentBSPixmapList[i] -> pSavedWindow = pWin; + nxagentBSPixmapList[i] -> backingStoreX = bsx; + nxagentBSPixmapList[i] -> backingStoreY = bsy; + + #ifdef TEST + fprintf(stderr, "nxagentAddItemBSPixmapList: Added Pixmap with id [%lu] to nxagentBSPixmapList.\n", id); + #endif + + return 1; + } + + if (nxagentBSPixmapList[i] -> storingPixmapId == id) + { + nxagentBSPixmapList[i] -> pStoringPixmap = pPixmap; + nxagentBSPixmapList[i] -> pSavedWindow = pWin; + nxagentBSPixmapList[i] -> backingStoreX = bsx; + nxagentBSPixmapList[i] -> backingStoreY = bsy; + + #ifdef TEST + fprintf(stderr, "nxagentAddItemBSPixmapList: Updated existing item for id [%lu].\n", id); + #endif + + return 1; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentAddItemBSPixmapList: WARNING! List item full.\n"); + #endif + + return 0; +} + +int nxagentRemoveItemBSPixmapList(unsigned long pixmapId) +{ + int i; + int j; + + if (pixmapId == 0 || nxagentBSPixmapList[0] == NULL) + { + return 0; + } + + for (i = 0; i < BSPIXMAPLIMIT; i++) + { + if ((nxagentBSPixmapList[i] != NULL) && + (nxagentBSPixmapList[i] -> storingPixmapId == pixmapId)) + { + free(nxagentBSPixmapList[i]); + nxagentBSPixmapList[i] = NULL; + + if (i < BSPIXMAPLIMIT - 1) + { + for (j = i; j < BSPIXMAPLIMIT -1; j++) + { + nxagentBSPixmapList[j] = nxagentBSPixmapList[j + 1]; + } + + if (nxagentBSPixmapList[j] == nxagentBSPixmapList[j - 1]) + { + nxagentBSPixmapList[j] = NULL; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentRemoveItemBSPixmapList: Removed Pixmap with id [%lu] from list.\n", + pixmapId); + #endif + + return 1; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentRemoveItemBSPixmapList: WARNING! Can't remove item [%lu]: item not found.\n", + pixmapId); + #endif + + return 0; +} + +int nxagentEmptyBSPixmapList() +{ + int i; + + for (i = 0; i < BSPIXMAPLIMIT; i++) + { + if (nxagentBSPixmapList[i] != NULL) + { + free(nxagentBSPixmapList[i]); + nxagentBSPixmapList[i] = NULL; + } + } + + return 1; +} + +StoringPixmapPtr nxagentFindItemBSPixmapList(unsigned long pixmapId) +{ + int i; + + for (i = 0; i < BSPIXMAPLIMIT; i++) + { + if ((nxagentBSPixmapList[i] != NULL) && + (nxagentBSPixmapList[i] -> storingPixmapId == pixmapId)) + { + #ifdef TEST + fprintf(stderr, "nxagentFindItemBSPixmapList: pixmapId [%lu].\n", pixmapId); + fprintf(stderr, "nxagentFindItemBSPixmapList: nxagentBSPixmapList[%d] -> storingPixmapId [%lu].\n", + i, nxagentBSPixmapList[i] -> storingPixmapId); + #endif + + return nxagentBSPixmapList[i]; + } + } + + #ifdef TEST + fprintf(stderr, "nxagentFindItemBSPixmapList: WARNING! Item not found.\n"); + #endif + + #ifdef TEST + fprintf(stderr, "nxagentFindItemBSPixmapList: Pixmap with id [%lu] not found.\n", + pixmapId); + fprintf(stderr, "nxagentBSPixmapList[%d] = [%p].\n", + i, (void *) nxagentBSPixmapList[i]); + #endif + + return NULL; +} + diff --git a/nx-X11/programs/Xserver/hw/nxagent/Windows.h b/nx-X11/programs/Xserver/hw/nxagent/Windows.h new file mode 100644 index 000000000..8612cdf82 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/Windows.h @@ -0,0 +1,328 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#ifndef __Window_H__ +#define __Window_H__ + +#include "Options.h" +#include "Rootless.h" +#include "Pixmaps.h" + +#include "validate.h" + +typedef struct +{ + Window window; + int x; + int y; + unsigned int width; + unsigned int height; + unsigned int borderWidth; + Window siblingAbove; + int backingStore; +#ifdef SHAPE + RegionPtr boundingShape; + RegionPtr clipShape; +#endif /* SHAPE */ + + void *pPicture; + + /* + * Set if the window is mapped + * on the remote server. + */ + + int isMapped; + + /* + * Set if the window on the remote + * server is redirected by using + * the composite extension. + */ + + int isRedirected; + + int visibilityState; + + RegionPtr corruptedRegion; + + int hasTransparentChildren; + + int containGlyphs; + + int deferredBackgroundExpose; + + XID corruptedId; + + PixmapPtr synchronizationBitmap; + + Time corruptedTimestamp; + + SplitResourcePtr splitResource; + +} nxagentPrivWindowRec; + +typedef nxagentPrivWindowRec *nxagentPrivWindowPtr; + +typedef struct +{ + unsigned long storingPixmapId; + + PixmapPtr pStoringPixmap; + + WindowPtr pSavedWindow; + + int backingStoreX; + + int backingStoreY; + +} StoringPixmapRec; + +typedef StoringPixmapRec *StoringPixmapPtr; + +int nxagentAddItemBSPixmapList(unsigned long, PixmapPtr, WindowPtr, int, int); +int nxagentRemoveItemBSPixmapList(unsigned long); +void nxagentInitBSPixmapList(void); +int nxagentEmptyBSPixmapList(void); +StoringPixmapPtr nxagentFindItemBSPixmapList (unsigned long); + +extern int nxagentWindowPrivateIndex; + +#define nxagentWindowPriv(pWin) \ + ((nxagentPrivWindowPtr)((pWin)->devPrivates[nxagentWindowPrivateIndex].ptr)) + +#define nxagentWindow(pWin) (nxagentWindowPriv(pWin)->window) + +/* + * Window is either a child of our root + * or a child of the root of the real X + * server. + */ + +#define nxagentWindowParent(pWin) \ + (nxagentOption(Rootless) ? \ + nxagentRootlessWindowParent(pWin) : \ + ((pWin)->parent ? \ + nxagentWindow((pWin)->parent) : \ + nxagentDefaultWindows[pWin->drawable.pScreen->myNum])) + +/* + * True if this is a top level window. + */ + +#define nxagentWindowTopLevel(pWin) \ + (pWin && (pWin -> parent == NULL || \ + pWin->parent == nxagentRootlessWindow)) + +#define nxagentWindowSiblingAbove(pWin) \ + ((pWin)->prevSib ? nxagentWindow((pWin)->prevSib) : None) + +#define nxagentWindowSiblingBelow(pWin) \ + ((pWin)->nextSib ? nxagentWindow((pWin)->nextSib) : None) + +#define nxagentWindowCorruptedRegion(pWin) \ + (nxagentWindowPriv(pWin) -> corruptedRegion) + +#define nxagentWindowContainGlyphs(pWin) \ + (nxagentWindowPriv(pWin) -> containGlyphs) + +#define nxagentWindowTimestamp(pWin) \ + (nxagentWindowPriv(pWin) -> corruptedTimestamp) + +#define nxagentWindowIsVisible(pWin) \ + ((pWin) -> viewable == 1 && \ + (pWin) -> drawable.class != InputOnly && \ + (pWin) -> visibility != VisibilityFullyObscured) + +#define nxagentDefaultWindowIsVisible() \ + (nxagentVisibility != VisibilityFullyObscured) + +#define CWParent CWSibling +#define CWStackingOrder CWStackMode + +#define CW_Map (1 << 15) +#define CW_Update (1 << 16) +#define CW_Shape (1 << 17) +#define CW_RootlessRestack (1 << 18) + +/* + * This force the agent to send exposures + * for all windows. + */ + +#define nxagentRefreshScreen() \ +do\ +{\ + nxagentRefreshWindows(screenInfo.screens[0]->root);\ +} while (0) + +WindowPtr nxagentWindowPtr(Window window); + +extern Atom serverCutProperty; + +/* + * If the rectangles in an exposed region exceed + * the number of 4, we let the function decide if + * it is better to send the window extents rather + * than the rectangles in the region. + */ + +int nxagentExtentsPredicate(int total); + +/* + * Agent's nested window procedures. Look also + * at Rootless.h for the rootless counterparts. + */ + +Bool nxagentCreateWindow(WindowPtr pWin); + +Bool nxagentDestroyWindow(WindowPtr pWin); + +Bool nxagentPositionWindow(WindowPtr pWin, int x, int y); + +Bool nxagentChangeWindowAttributes(WindowPtr pWin, unsigned long mask); + +Bool nxagentRealizeWindow(WindowPtr pWin); + +Bool nxagentUnrealizeWindow(WindowPtr pWin); + +Bool nxagentCheckIllegalRootMonitoring(WindowPtr pWin, Mask mask); + +void nxagentWindowExposures(WindowPtr pWin, RegionPtr pRgn, RegionPtr other_exposed); + +void nxagentPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what); + +void nxagentPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what); + +void nxagentCopyWindow(WindowPtr pWin, xPoint oldOrigin, RegionPtr oldRegion); + +void nxagentClipNotify(WindowPtr pWin, int dx, int dy); + +void nxagentRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib); + +void nxagentReparentWindow(WindowPtr pWin, WindowPtr pOldParent); + +void nxagentRefreshWindows(WindowPtr pWin); + +void nxagentSetTopLevelEventMask(WindowPtr pWin); + +void nxagentSwitchFullscreen(ScreenPtr pScreen, Bool switchOn); + +void nxagentSwitchAllScreens(ScreenPtr pScreen, Bool switchOn); + +void nxagentMoveViewport(ScreenPtr pScreen, int hShift, int vShift); + +#ifdef VIEWPORT_FRAME + +void nxagentUpdateViewportFrame(int x, int y, int w, int h); + +#else /* #ifdef VIEWPORT_FRAME */ + +#define nxagentUpdateViewportFrame(x, y, w, h) + +#endif /* #ifdef VIEWPORT_FRAME */ + +void nxagentUnmapWindows(void); + +void nxagentMapDefaultWindows(void); + +Bool nxagentSetWindowCursors(void *p0); + +/* + * The ConfigureWindow procedure has not + * a pointer in the screen structure. + */ + +void nxagentConfigureWindow(WindowPtr pWin, unsigned int mask); + +/* + * Used to track nxagent window's visibility. + */ + +extern int nxagentVisibility; +extern unsigned long nxagentVisibilityTimeout; +extern Bool nxagentVisibilityStop; + +/* + * Return the pointer to the window given the + * remote id. It tries to match the id from + * the last matched window before iterating + * through the hierarchy. + */ + +WindowPtr nxagentGetWindowFromID(Window id); + +/* + * Handle the shape bitmap for windows. + */ + +#ifdef SHAPE + +void nxagentShapeWindow(WindowPtr pWin); + +#endif + +extern Window nxagentConfiguredSynchroWindow; +extern Bool nxagentExposeArrayIsInitialized; + +typedef struct _ConfiguredWindow +{ + WindowPtr pWin; + struct _ConfiguredWindow *next; + struct _ConfiguredWindow *prev; + unsigned int valuemask; +} ConfiguredWindowStruct; + +ConfiguredWindowStruct *nxagentConfiguredWindowList; + +typedef struct _StaticResizedWindow +{ + WindowPtr pWin; + struct _StaticResizedWindow *next; + struct _StaticResizedWindow *prev; + unsigned long sequence; + int offX; + int offY; +} StaticResizedWindowStruct; + +StaticResizedWindowStruct *nxagentStaticResizedWindowList; + +void nxagentPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind); + +void nxagentFlushConfigureWindow(void); + +void nxagentAddConfiguredWindow(WindowPtr pWin, unsigned int valuemask); + +void nxagentDeleteConfiguredWindow(WindowPtr pWin); + +void nxagentAddStaticResizedWindow(WindowPtr pWin, unsigned long sequence, int offX, int offY); + +void nxagentDeleteStaticResizedWindow(unsigned long sequence); + +StaticResizedWindowStruct *nxagentFindStaticResizedWindow(unsigned long sequence); + +void nxagentEmptyAllBackingStoreRegions(void); + +#endif /* __Window_H__ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xcomposite_nxagent.h b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xcomposite_nxagent.h new file mode 100644 index 000000000..ba3668015 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xcomposite_nxagent.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Copyright © 2003 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file is a reduced version of the header file of + * <X11/extensions/Xcomposite.h> + * + * This copy of code has been introduced to allow a clear namespace + * separation between <X11/...> and <nx-X11/...> header files. + * + * This version of the Xcomposite library header file only contains symbols + * required by nxagent and strictly avoids indirectly including + * from an X11 library that is also shipped in nx-X11/lib/. + * + * When using <X11/extensions/Xcomposite.h> instead for inclusion in + * nxagent, it will attempt pulling in the <X11/extensions/Xlib.h>. + * However, the headers of the same name from <nx-X11/...> should be + * used instead. + * + * FIXME: Once the nxagent Xserver starts using libX11 from X.Org, this + * hack can be removed. + * + * 2016/04/07, Mike Gabriel <mike.gabriel@das-netzwerkteam.de> + */ + +#ifndef _XCOMPOSITE_H_ +#define _XCOMPOSITE_H_ + +#include <X11/extensions/composite.h> +#include <nx-X11/Xfuncproto.h> + +/* + * This revision number also appears in configure.ac, they have + * to be manually synchronized + */ +#define XCOMPOSITE_MAJOR COMPOSITE_MAJOR +#define XCOMPOSITE_MINOR COMPOSITE_MINOR +#define XCOMPOSITE_REVISION 2 +#define XCOMPOSITE_VERSION ((XCOMPOSITE_MAJOR * 10000) + (XCOMPOSITE_MINOR * 100) + (XCOMPOSITE_REVISION)) + +_XFUNCPROTOBEGIN + +Bool XCompositeQueryExtension (Display *dpy, + int *event_base_return, + int *error_base_return); + +Status XCompositeQueryVersion (Display *dpy, + int *major_version_return, + int *minor_version_return); + +void +XCompositeRedirectWindow (Display *dpy, Window window, int update); + +void +XCompositeRedirectSubwindows (Display *dpy, Window window, int update); + +void +XCompositeUnredirectWindow (Display *dpy, Window window, int update); + +void +XCompositeUnredirectSubwindows (Display *dpy, Window window, int update); + +_XFUNCPROTOEND + +#endif /* _XCOMPOSITE_H_ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xfixes_nxagent.h b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xfixes_nxagent.h new file mode 100644 index 000000000..cbe64fbba --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xfixes_nxagent.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file is a reduced version of the header file of + * <X11/extensions/Xfixes.h> + * + * This copy of code has been introduced to allow a clear namespace + * separation between <X11/...> and <nx-X11/...> header files. + * + * This version of the Xfixes library header file only contains symbols + * required by nxagent and strictly avoids indirectly including + * from an X11 library that is also shipped in nx-X11/lib/. + * + * When using <X11/extensions/Xfixes.h> instead for inclusion in + * nxagent, it will attempt pulling in the <X11/extensions/Xlib.h>. + * However, the headers of the same name from <nx-X11/...> should be + * used instead. + * + * FIXME: Once the nxagent Xserver starts using libX11 from X.Org, this + * hack can be removed. + * + * 2015/12/28, Mike Gabriel <mike.gabriel@das-netzwerkteam.de> + */ + +#ifndef _XFIXES_H_ +#define _XFIXES_H_ + +typedef struct { + int type; /* event base */ + unsigned long serial; + Bool send_event; + Display *display; + Window window; + int subtype; + Window owner; + Atom selection; + Time timestamp; + Time selection_timestamp; +} XFixesSelectionNotifyEvent; + +void +XFixesSelectSelectionInput (Display *dpy, + Window win, + Atom selection, + unsigned long eventMask); + +#endif /* _XFIXES_H_ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xinerama_nxagent.h b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xinerama_nxagent.h new file mode 100644 index 000000000..210c4b5e7 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xinerama_nxagent.h @@ -0,0 +1,74 @@ +/* + +Copyright 2003 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#ifndef _Xinerama_h +#define _Xinerama_h + +#include <nx-X11/Xlib.h> + +typedef struct { + int screen_number; + short x_org; + short y_org; + short width; + short height; +} XineramaScreenInfo; + +_XFUNCPROTOBEGIN + +Bool XineramaQueryExtension ( + Display *dpy, + int *event_base, + int *error_base +); + +Status XineramaQueryVersion( + Display *dpy, + int *major_versionp, + int *minor_versionp +); + +Bool XineramaIsActive(Display *dpy); + + +/* + Returns the number of heads and a pointer to an array of + structures describing the position and size of the individual + heads. Returns NULL and number = 0 if Xinerama is not active. + + Returned array should be freed with XFree(). +*/ + +XineramaScreenInfo * +XineramaQueryScreens( + Display *dpy, + int *number +); + +_XFUNCPROTOEND + +#endif /* _Xinerama_h */ + diff --git a/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xrandr_nxagent.h b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xrandr_nxagent.h new file mode 100644 index 000000000..02f3356e4 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xrandr_nxagent.h @@ -0,0 +1,83 @@ +/* + * Copyright © 2000 Compaq Computer Corporation, Inc. + * Copyright © 2002 Hewlett-Packard Company, Inc. + * Copyright © 2006 Intel Corporation + * Copyright © 2008 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Author: Jim Gettys, HP Labs, Hewlett-Packard, Inc. + * Keith Packard, Intel Corporation + */ + +/* + * This file is a reduced version of the header file of + * <X11/extensions/Xrandr.h> + * + * This copy of code has been introduced to allow a clear namespace + * separation between <X11/...> and <nx-X11/...> header files. + * + * This version of the Xrandr library header file only contains symbols + * required by nxagent and strictly avoids indirectly including + * from an X11 library that is also shipped in nx-X11/lib/. + * + * When using <X11/extensions/Xrandr.h> instead for inclusion in + * nxagent, it will attempt pulling in the <X11/extensions/Xrender.h> + * header which in turn will include <X11/Xlib.h>. However, the headers of + * the same name from <nx-X11/...> should be used instead. + * + * FIXME: Once the nxagent Xserver starts using libXrender from X.Org, this + * hack can be removed. + * + * 2015/06/26, Mike Gabriel <mike.gabriel@das-netzwerkteam.de> + */ + +#ifndef _XRANDR_H_ +#define _XRANDR_H_ + +#include <nx-X11/extensions/randr.h> +#include <nx-X11/Xfuncproto.h> + +_XFUNCPROTOBEGIN + +/* + * Events. + */ + +typedef struct { + int type; /* event base */ + unsigned long serial; /* # of last request processed by server */ + Bool send_event; /* true if this came from a SendEvent request */ + Display *display; /* Display the event was read from */ + Window window; /* window which selected for this event */ + Window root; /* Root window for changed screen */ + Time timestamp; /* when the screen change occurred */ + Time config_timestamp; /* when the last configuration change */ + SizeID size_index; + SubpixelOrder subpixel_order; + Rotation rotation; + int width; + int height; + int mwidth; + int mheight; +} XRRScreenChangeNotifyEvent; + +_XFUNCPROTOEND + +#endif /* _XRANDR_H_ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xrender_nxagent.h b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xrender_nxagent.h new file mode 100644 index 000000000..488132172 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xrender_nxagent.h @@ -0,0 +1,528 @@ +/* + * + * Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Keith Packard, SuSE, Inc. + */ + +#ifndef _XRENDER_H_ +#define _XRENDER_H_ + +#include <nx-X11/Xlib.h> +#include <nx-X11/Xfuncproto.h> +#include <nx-X11/Xosdefs.h> +#include <nx-X11/Xutil.h> + +#include <nx-X11/extensions/render.h> + +typedef struct { + short red; + short redMask; + short green; + short greenMask; + short blue; + short blueMask; + short alpha; + short alphaMask; +} XRenderDirectFormat; + +typedef struct { + PictFormat id; + int type; + int depth; + XRenderDirectFormat direct; + Colormap colormap; +} XRenderPictFormat; + +#define PictFormatID (1 << 0) +#define PictFormatType (1 << 1) +#define PictFormatDepth (1 << 2) +#define PictFormatRed (1 << 3) +#define PictFormatRedMask (1 << 4) +#define PictFormatGreen (1 << 5) +#define PictFormatGreenMask (1 << 6) +#define PictFormatBlue (1 << 7) +#define PictFormatBlueMask (1 << 8) +#define PictFormatAlpha (1 << 9) +#define PictFormatAlphaMask (1 << 10) +#define PictFormatColormap (1 << 11) + +typedef struct _XRenderPictureAttributes { + int repeat; + Picture alpha_map; + int alpha_x_origin; + int alpha_y_origin; + int clip_x_origin; + int clip_y_origin; + Pixmap clip_mask; + Bool graphics_exposures; + int subwindow_mode; + int poly_edge; + int poly_mode; + Atom dither; + Bool component_alpha; +} XRenderPictureAttributes; + +typedef struct { + unsigned short red; + unsigned short green; + unsigned short blue; + unsigned short alpha; +} XRenderColor; + +typedef struct _XGlyphInfo { + unsigned short width; + unsigned short height; + short x; + short y; + short xOff; + short yOff; +} XGlyphInfo; + +typedef struct _XGlyphElt8 { + GlyphSet glyphset; + _Xconst char *chars; + int nchars; + int xOff; + int yOff; +} XGlyphElt8; + +typedef struct _XGlyphElt16 { + GlyphSet glyphset; + _Xconst unsigned short *chars; + int nchars; + int xOff; + int yOff; +} XGlyphElt16; + +typedef struct _XGlyphElt32 { + GlyphSet glyphset; + _Xconst unsigned int *chars; + int nchars; + int xOff; + int yOff; +} XGlyphElt32; + +typedef double XDouble; + +typedef struct _XPointDouble { + XDouble x, y; +} XPointDouble; + +#define XDoubleToFixed(f) ((XFixed) ((f) * 65536)) +#define XFixedToDouble(f) (((XDouble) (f)) / 65536) + +typedef int XFixed; + +typedef struct _XPointFixed { + XFixed x, y; +} XPointFixed; + +typedef struct _XLineFixed { + XPointFixed p1, p2; +} XLineFixed; + +typedef struct _XTriangle { + XPointFixed p1, p2, p3; +} XTriangle; + +typedef struct _XCircle { + XFixed x; + XFixed y; + XFixed radius; +} XCircle; + +typedef struct _XTrapezoid { + XFixed top, bottom; + XLineFixed left, right; +} XTrapezoid; + +typedef struct _XTransform { + XFixed matrix[3][3]; +} XTransform; + +typedef struct _XFilters { + int nfilter; + char **filter; + int nalias; + short *alias; +} XFilters; + +typedef struct _XIndexValue { + unsigned long pixel; + unsigned short red, green, blue, alpha; +} XIndexValue; + +typedef struct _XAnimCursor { + Cursor cursor; + unsigned long delay; +} XAnimCursor; + +typedef struct _XSpanFix { + XFixed left, right, y; +} XSpanFix; + +typedef struct _XTrap { + XSpanFix top, bottom; +} XTrap; + +typedef struct _XLinearGradient { + XPointFixed p1; + XPointFixed p2; +} XLinearGradient; + +typedef struct _XRadialGradient { + XCircle inner; + XCircle outer; +} XRadialGradient; + +typedef struct _XConicalGradient { + XPointFixed center; + XFixed angle; /* in degrees */ +} XConicalGradient; + +_XFUNCPROTOBEGIN + +Bool XRenderQueryExtension (Display *dpy, int *event_basep, int *error_basep); + +Status XRenderQueryVersion (Display *dpy, + int *major_versionp, + int *minor_versionp); + +Status XRenderQueryFormats (Display *dpy); + +int XRenderQuerySubpixelOrder (Display *dpy, int screen); + +Bool XRenderSetSubpixelOrder (Display *dpy, int screen, int subpixel); + +XRenderPictFormat * +XRenderFindVisualFormat (Display *dpy, _Xconst Visual *visual); + +XRenderPictFormat * +XRenderFindFormat (Display *dpy, + unsigned long mask, + _Xconst XRenderPictFormat *templ, + int count); + +#define PictStandardARGB32 0 +#define PictStandardRGB24 1 +#define PictStandardA8 2 +#define PictStandardA4 3 +#define PictStandardA1 4 +#define PictStandardNUM 5 + +XRenderPictFormat * +XRenderFindStandardFormat (Display *dpy, + int format); + +XIndexValue * +XRenderQueryPictIndexValues(Display *dpy, + _Xconst XRenderPictFormat *format, + int *num); + +Picture +XRenderCreatePicture (Display *dpy, + Drawable drawable, + _Xconst XRenderPictFormat *format, + unsigned long valuemask, + _Xconst XRenderPictureAttributes *attributes); + +void +XRenderChangePicture (Display *dpy, + Picture picture, + unsigned long valuemask, + _Xconst XRenderPictureAttributes *attributes); + +void +XRenderSetPictureClipRectangles (Display *dpy, + Picture picture, + int xOrigin, + int yOrigin, + _Xconst XRectangle *rects, + int n); + +void +XRenderSetPictureClipRegion (Display *dpy, + Picture picture, + Region r); + +void +XRenderSetPictureTransform (Display *dpy, + Picture picture, + XTransform *transform); + +void +XRenderFreePicture (Display *dpy, + Picture picture); + +void +XRenderComposite (Display *dpy, + int op, + Picture src, + Picture mask, + Picture dst, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height); + +GlyphSet +XRenderCreateGlyphSet (Display *dpy, _Xconst XRenderPictFormat *format); + +GlyphSet +XRenderReferenceGlyphSet (Display *dpy, GlyphSet existing); + +void +XRenderFreeGlyphSet (Display *dpy, GlyphSet glyphset); + +void +XRenderAddGlyphs (Display *dpy, + GlyphSet glyphset, + _Xconst Glyph *gids, + _Xconst XGlyphInfo *glyphs, + int nglyphs, + _Xconst char *images, + int nbyte_images); + +void +XRenderFreeGlyphs (Display *dpy, + GlyphSet glyphset, + _Xconst Glyph *gids, + int nglyphs); + +void +XRenderCompositeString8 (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + GlyphSet glyphset, + int xSrc, + int ySrc, + int xDst, + int yDst, + _Xconst char *string, + int nchar); + +void +XRenderCompositeString16 (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + GlyphSet glyphset, + int xSrc, + int ySrc, + int xDst, + int yDst, + _Xconst unsigned short *string, + int nchar); + +void +XRenderCompositeString32 (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + GlyphSet glyphset, + int xSrc, + int ySrc, + int xDst, + int yDst, + _Xconst unsigned int *string, + int nchar); + +void +XRenderCompositeText8 (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + int xSrc, + int ySrc, + int xDst, + int yDst, + _Xconst XGlyphElt8 *elts, + int nelt); + +void +XRenderCompositeText16 (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + int xSrc, + int ySrc, + int xDst, + int yDst, + _Xconst XGlyphElt16 *elts, + int nelt); + +void +XRenderCompositeText32 (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + int xSrc, + int ySrc, + int xDst, + int yDst, + _Xconst XGlyphElt32 *elts, + int nelt); + +void +XRenderFillRectangle (Display *dpy, + int op, + Picture dst, + _Xconst XRenderColor *color, + int x, + int y, + unsigned int width, + unsigned int height); + +void +XRenderFillRectangles (Display *dpy, + int op, + Picture dst, + _Xconst XRenderColor *color, + _Xconst XRectangle *rectangles, + int n_rects); + +void +XRenderCompositeTrapezoids (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + int xSrc, + int ySrc, + _Xconst XTrapezoid *traps, + int ntrap); + +void +XRenderCompositeTriangles (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + int xSrc, + int ySrc, + _Xconst XTriangle *triangles, + int ntriangle); + +void +XRenderCompositeTriStrip (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + int xSrc, + int ySrc, + _Xconst XPointFixed *points, + int npoint); + +void +XRenderCompositeTriFan (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + int xSrc, + int ySrc, + _Xconst XPointFixed *points, + int npoint); + +void +XRenderCompositeDoublePoly (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + int xSrc, + int ySrc, + int xDst, + int yDst, + _Xconst XPointDouble *fpoints, + int npoints, + int winding); +Status +XRenderParseColor(Display *dpy, + char *spec, + XRenderColor *def); + +Cursor +XRenderCreateCursor (Display *dpy, + Picture source, + unsigned int x, + unsigned int y); + +XFilters * +XRenderQueryFilters (Display *dpy, Drawable drawable); + +void +XRenderSetPictureFilter (Display *dpy, + Picture picture, + const char *filter, + XFixed *params, + int nparams); + +Cursor +XRenderCreateAnimCursor (Display *dpy, + int ncursor, + XAnimCursor *cursors); + + +void +XRenderAddTraps (Display *dpy, + Picture picture, + int xOff, + int yOff, + _Xconst XTrap *traps, + int ntrap); + +Picture XRenderCreateSolidFill (Display *dpy, + const XRenderColor *color); + +Picture XRenderCreateLinearGradient (Display *dpy, + const XLinearGradient *gradient, + const XFixed *stops, + const XRenderColor *colors, + int nstops); + +Picture XRenderCreateRadialGradient (Display *dpy, + const XRadialGradient *gradient, + const XFixed *stops, + const XRenderColor *colors, + int nstops); + +Picture XRenderCreateConicalGradient (Display *dpy, + const XConicalGradient *gradient, + const XFixed *stops, + const XRenderColor *colors, + int nstops); + +_XFUNCPROTOEND + +#endif /* _XRENDER_H_ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xrenderint_nxagent.h b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xrenderint_nxagent.h new file mode 100644 index 000000000..ff14aa26a --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/X11/include/Xrenderint_nxagent.h @@ -0,0 +1,106 @@ +/* + * + * Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Keith Packard, SuSE, Inc. + */ + +#ifndef _XRENDERINT_H_ +#define _XRENDERINT_H_ + +#include <nx-X11/Xlibint.h> +#include <nx-X11/Xutil.h> +#include <nx-X11/extensions/renderproto.h> +#include "Xrender_nxagent.h" + +typedef struct { + Visual *visual; + XRenderPictFormat *format; +} XRenderVisual; + +typedef struct { + int depth; + int nvisuals; + XRenderVisual *visuals; +} XRenderDepth; + +typedef struct { + XRenderDepth *depths; + int ndepths; + XRenderPictFormat *fallback; + int subpixel; +} XRenderScreen; + +typedef struct _XRenderInfo { + int major_version; + int minor_version; + XRenderPictFormat *format; + int nformat; + XRenderScreen *screen; + int nscreen; + XRenderDepth *depth; + int ndepth; + XRenderVisual *visual; + int nvisual; + int *subpixel; + int nsubpixel; + char **filter; + int nfilter; + short *filter_alias; + int nfilter_alias; +} XRenderInfo; + +/* replaces XRenderExtDisplayInfo */ +typedef struct _XRenderExtDisplayInfo { + struct _XRenderExtDisplayInfo *next; /* keep a linked list */ + Display *display; /* which display this is */ + XExtCodes *codes; /* the extension protocol codes */ + XRenderInfo *info; /* extra data for the extension to use */ +} XRenderExtDisplayInfo; + +/* replaces XExtensionInfo */ +typedef struct _XRenderExtInfo { + XRenderExtDisplayInfo *head; /* start of the list */ + XRenderExtDisplayInfo *cur; /* most recently used */ + int ndisplays; /* number of displays */ +} XRenderExtInfo; + +extern XRenderExtInfo XRenderExtensionInfo; +extern char XRenderExtensionName[]; + +XRenderExtDisplayInfo * +XRenderFindDisplay (Display *dpy); + +#define RenderHasExtension(i) ((i) && ((i)->codes)) + +#define RenderCheckExtension(dpy,i,val) \ + if (!RenderHasExtension(i)) { return val; } + +#define RenderSimpleCheckExtension(dpy,i) \ + if (!RenderHasExtension(i)) { return; } + +/* + * Xlib uses long for 32-bit values. Xrender uses int. This + * matters on alpha. Note that this macro assumes that int is 32 bits. + */ + +#define DataInt32(dpy,d,len) Data(dpy,(char *) (d),len) + +#endif /* _XRENDERINT_H_ */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/X11/include/xpm_nxagent.h b/nx-X11/programs/Xserver/hw/nxagent/X11/include/xpm_nxagent.h new file mode 100644 index 000000000..b02e5a913 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/X11/include/xpm_nxagent.h @@ -0,0 +1,259 @@ +/* + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +/*****************************************************************************\ +* xpm.h: * +* * +* XPM library * +* Include file * +* * +* Developed by Arnaud Le Hors * +\*****************************************************************************/ + +/* + * This file is a reduced version of the header file of + * <X11/xpm.h> + * + * This copy of code has been introduced to allow a clear namespace + * separation between <X11/...> and <nx-X11/...> header files. + * + * This version of the Xpm library header file only contains symbols + * required by nxagent and strictly avoids indirectly including + * from an X11 library that is also shipped in nx-X11/lib/. + * + * When using <X11/xpm.h> instead for inclusion in nxagent, it will + * attempt pulling in the <X11/extensions/Xlib.h> header file. + * However, the headers of the same name from <nx-X11/...> should be + * used instead. + * + * FIXME: Once the nxagent Xserver starts using libX11 from X.Org, this + * hack can be removed. + * + * 2015/06/26, Mike Gabriel <mike.gabriel@das-netzwerkteam.de> + */ + +#ifndef XPM_h +#define XPM_h + +/* + * first some identification numbers: + * the version and revision numbers are determined with the following rule: + * SO Major number = LIB minor version number. + * SO Minor number = LIB sub-minor version number. + * e.g: Xpm version 3.2f + * we forget the 3 which is the format number, 2 gives 2, and f gives 6. + * thus we have XpmVersion = 2 and XpmRevision = 6 + * which gives SOXPMLIBREV = 2.6 + * + * Then the XpmIncludeVersion number is built from these numbers. + */ +#define XpmFormat 3 +#define XpmVersion 4 +#define XpmRevision 11 +#define XpmIncludeVersion ((XpmFormat * 100 + XpmVersion) * 100 + XpmRevision) + +#ifndef XPM_NUMBERS + +/* let's define Pixel if it is not done yet */ +#if ! defined(_XtIntrinsic_h) && ! defined(PIXEL_ALREADY_TYPEDEFED) +typedef unsigned long Pixel; /* Index into colormap */ +# define PIXEL_ALREADY_TYPEDEFED +#endif + +/* include headers from <nx-X11/...> instead of <X11/...> */ +#include <nx-X11/Xlib.h> +#include <nx-X11/Xutil.h> + +/* Return ErrorStatus codes: + * null if full success + * positive if partial success + * negative if failure + */ + +#define XpmColorError 1 +#define XpmSuccess 0 +#define XpmOpenFailed -1 +#define XpmFileInvalid -2 +#define XpmNoMemory -3 +#define XpmColorFailed -4 + +typedef struct { + char *name; /* Symbolic color name */ + char *value; /* Color value */ + Pixel pixel; /* Color pixel */ +} XpmColorSymbol; + +typedef struct { + char *name; /* name of the extension */ + unsigned int nlines; /* number of lines in this extension */ + char **lines; /* pointer to the extension array of strings */ +} XpmExtension; + +typedef struct { + char *string; /* characters string */ + char *symbolic; /* symbolic name */ + char *m_color; /* monochrom default */ + char *g4_color; /* 4 level grayscale default */ + char *g_color; /* other level grayscale default */ + char *c_color; /* color default */ +} XpmColor; + +typedef struct { + unsigned int width; /* image width */ + unsigned int height; /* image height */ + unsigned int cpp; /* number of characters per pixel */ + unsigned int ncolors; /* number of colors */ + XpmColor *colorTable; /* list of related colors */ + unsigned int *data; /* image data */ +} XpmImage; + +typedef struct { + unsigned long valuemask; /* Specifies which attributes are defined */ + char *hints_cmt; /* Comment of the hints section */ + char *colors_cmt; /* Comment of the colors section */ + char *pixels_cmt; /* Comment of the pixels section */ + unsigned int x_hotspot; /* Returns the x hotspot's coordinate */ + unsigned int y_hotspot; /* Returns the y hotspot's coordinate */ + unsigned int nextensions; /* number of extensions */ + XpmExtension *extensions; /* pointer to array of extensions */ +} XpmInfo; + +typedef int (*XpmAllocColorFunc)( + Display* /* display */, + Colormap /* colormap */, + char* /* colorname */, + XColor* /* xcolor */, + void* /* closure */ +); + +typedef int (*XpmFreeColorsFunc)( + Display* /* display */, + Colormap /* colormap */, + Pixel* /* pixels */, + int /* npixels */, + void* /* closure */ +); + + +/* required struct for hw/nxagent/Holder.c */ +typedef struct { + unsigned long valuemask; /* Specifies which attributes are + defined */ + + Visual *visual; /* Specifies the visual to use */ + Colormap colormap; /* Specifies the colormap to use */ + unsigned int depth; /* Specifies the depth */ + unsigned int width; /* Returns the width of the created + pixmap */ + unsigned int height; /* Returns the height of the created + pixmap */ + unsigned int x_hotspot; /* Returns the x hotspot's + coordinate */ + unsigned int y_hotspot; /* Returns the y hotspot's + coordinate */ + unsigned int cpp; /* Specifies the number of char per + pixel */ + Pixel *pixels; /* List of used color pixels */ + unsigned int npixels; /* Number of used pixels */ + XpmColorSymbol *colorsymbols; /* List of color symbols to override */ + unsigned int numsymbols; /* Number of symbols */ + char *rgb_fname; /* RGB text file name */ + unsigned int nextensions; /* Number of extensions */ + XpmExtension *extensions; /* List of extensions */ + + unsigned int ncolors; /* Number of colors */ + XpmColor *colorTable; /* List of colors */ +/* 3.2 backward compatibility code */ + char *hints_cmt; /* Comment of the hints section */ + char *colors_cmt; /* Comment of the colors section */ + char *pixels_cmt; /* Comment of the pixels section */ +/* end 3.2 bc */ + unsigned int mask_pixel; /* Color table index of transparent + color */ + + /* Color Allocation Directives */ + Bool exactColors; /* Only use exact colors for visual */ + unsigned int closeness; /* Allowable RGB deviation */ + unsigned int red_closeness; /* Allowable red deviation */ + unsigned int green_closeness; /* Allowable green deviation */ + unsigned int blue_closeness; /* Allowable blue deviation */ + int color_key; /* Use colors from this color set */ + + Pixel *alloc_pixels; /* Returns the list of alloc'ed color + pixels */ + int nalloc_pixels; /* Returns the number of alloc'ed + color pixels */ + + Bool alloc_close_colors; /* Specify whether close colors should + be allocated using XAllocColor + or not */ + int bitmap_format; /* Specify the format of 1bit depth + images: ZPixmap or XYBitmap */ + + /* Color functions */ + XpmAllocColorFunc alloc_color; /* Application color allocator */ + XpmFreeColorsFunc free_colors; /* Application color de-allocator */ + void *color_closure; /* Application private data to pass to + alloc_color and free_colors */ + +} XpmAttributes; + +/* XpmAttributes value masks bits */ + +/* required masks bits for hw/nxagent/Holder.c */ +#define XpmDepth (1L<<2) +#define XpmSize (1L<<3) /* width & height */ + +/* macros for forward declarations of functions with prototypes */ +#define FUNC(f, t, p) extern t f p +#define LFUNC(f, t, p) static t f p + + +/* + * functions declarations (for building nxagent against system wide libXpm4, + * but also against libNX_X11 (as opposed to system-wide libX11). + */ + +_XFUNCPROTOBEGIN + +/* Keep for hw/nxagent/Holder.c */ +FUNC(XpmCreatePixmapFromData, int, (Display *display, + Drawable d, + char **data, + Pixmap *pixmap_return, + Pixmap *shapemask_return, + XpmAttributes *attributes)); +/* Keep for hw/nxagent/Display.c */ +FUNC(XpmReadFileToPixmap, int, (Display *display, + Drawable d, + const char *filename, + Pixmap *pixmap_return, + Pixmap *shapemask_return, + XpmAttributes *attributes)); + +_XFUNCPROTOEND + +#endif /* XPM_NUMBERS */ +#endif 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..8a53da376 --- /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; + + _X_UNUSED 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[]) +{ + _X_UNUSED 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) +{ + _X_UNUSED register xReq *req; + + _NXCollectInputFocusState *state; + _XAsyncHandler *handler; + + if (resource >= NXNumberOfResources) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectInputFocus: PANIC! Provided resource [%u] is out of range.\n", + resource); + #endif + + return -1; + } + + state = _NXCollectedInputFocuses[resource]; + + if (state != NULL) + { + #ifdef PANIC + fprintf(stderr, "******NXCollectInputFocus: PANIC! Having to remove previous state for resource [%u].\n", + resource); + #endif + + if (state -> handler != NULL) + { + DeqAsyncHandler(dpy, state -> handler); + + 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 */ diff --git a/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 b/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 new file mode 100644 index 000000000..1abec5753 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/man/nxagent.1 @@ -0,0 +1,1050 @@ + +.\" Copyright 1984 - 1991, 1993, 1994, 1998 The Open Group +.\" Copyright 2011 - 2016, Mike Gabriel <mike.gabriel@das-netzwerkteam.de> +.\" +.\" Permission to use, copy, modify, distribute, and sell this software and its +.\" documentation for any purpose is hereby granted without fee, provided that +.\" the above copyright notice appear in all copies and that both that +.\" copyright notice and this permission notice appear in supporting +.\" documentation. +.\" +.\" The above copyright notice and this permission notice shall be included +.\" in all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +.\" IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +.\" OTHER DEALINGS IN THE SOFTWARE. +.\" +.\" Except as contained in this notice, the name of The Open Group shall +.\" not be used in advertising or otherwise to promote the sale, use or +.\" other dealings in this Software without prior written authorization +.\" from The Open Group. +.ds q \N'34' +.TH nxagent 1 "April 2017" "Version 3.6.x" "NX Agent (Xserver)" +.SH NAME +nxagent \- nested Xserver optimized for remote computing +.SH SYNOPSIS +.B nxagent +.I "[options]" +.SH DESCRIPTION +\fBnxagent\fR is an X server for remote application/desktop access +similar to Xnest or Xephyr. +.PP +\fBnxagent\fR implements a very efficient compression of the X11 +protocol, called the NX protocol. +.PP +The NX protocol increases performance when using X applications over high +latency and low bandwidth networks, while providing a local (LAN-like) +usage experience even if connecting from off-site locations (via cable +modem or GSM). +.PP +\fBnxagent\fR can be used standalone as a nested X server (with NX +protocol disabled), but its real benefits are gained when using it over +remote connections via the nxcomp compression library. The counterpart +application on the other end (i.e. the client) is called +\fBnxproxy\fR. +.PP +When used in proxy <-> agent mode, \fBnxagent\fR adds the feature of +being suspendible. Sessions can be started from one client, suspended and +then resumed from another (or the same) client. +.PP +\fBnxagent\fR and \fBnxproxy\fR are utilized by various remote +application/desktop frameworks for providing server-side GUI application +access from remote client systems. +.PP +Currently, \fBnxagent\fR is co-maintained by three of these projects: The +Arctica Project, TheQVD and X2Go. +.PP + +.SH "STARTING THE SERVER" +\fBnxagent\fR should be run in user space. Other than the system's +local X.org server, \fBnxagent\fR does not require to be run as root. +When bundled with a remote application framework, you normally don't have +to launch \fBnxagent\fR manually. \fBnxagent\fR startup is usually +managed by the underlying framework (e.g. Arctica Session Manager, X2Go +Server, etc.). +.PP +When \fBnxagent\fR starts up (e.g. by typing 'nxagent -ac :1' in a +terminal window), it typically launches in "windowed desktop" mode. On +your local X server a new window appears being an X server itself. +.PP +However, \fBnxagent\fR also supports rootless (or seamless) application +mode and a shadow session mode (similar to what VNC does). +.PP +Example: You can launch a complete desktop session inside this nested X +server now: +.TP 8 +The Debian way... +.PP +.nf + $ export DISPLAY=:1 + $ STARTUP=mate-session /etc/X11/Xsession +.fi +.TP 8 +The Fedora / Gentoo / openSUSE way... +.PP +.nf + ### FIXME / TODO ### +.fi +.PP +However, \fBnxagent\fR also supports rootless (or seamless) application +mode and a shadow session mode (similar to what VNC does). + +.SH OPTIONS +\fBnxagent\fR accepts a range of default X server options as described +below. Those default options have to be provided via the command line. + +Furthermore, \fBnxagent\fR accepts some nx-X11 specific options, +described further below. + +Last but not least, \fBnxagent\fR accepts several more options, the +so-called nx/nx options, provided via the $DISPLAY environment +variable or the -options command line option. See below for further +details. + +.SH STANDARD XSERVER OPTIONS +.TP 8 +.B :\fIdisplaynumber\fP +The X server runs as the given \fIdisplaynumber\fP, which by default is 0. +If multiple X servers are to run simultaneously on a host, each must have +a unique display number. See the DISPLAY +NAMES section of the \fIX\fP(__miscmansuffix__) manual page to learn how to +specify which display number clients should try to use. +.TP 8 +.B \-a \fInumber\fP +sets pointer acceleration (i.e. the ratio of how much is reported to how much +the user actually moved the pointer). +.TP 8 +.B \-ac +disables host-based access control mechanisms. Enables access by any host, +and permits any host to modify the access control list. +Use with extreme caution. +This option exists primarily for running test suites remotely. +.TP 8 +.B \-audit \fIlevel\fP +sets the audit trail level. The default level is 1, meaning only connection +rejections are reported. Level 2 additionally reports all successful +connections and disconnects. Level 4 enables messages from the +SECURITY extension, if present, including generation and revocation of +authorizations and violations of the security policy. +Level 0 turns off the audit trail. +Audit lines are sent as standard error output. +.TP 8 +.B \-auth \fIauthorization-file\fP +specifies a file which contains a collection of authorization records used +to authenticate access. See also the \fIxdm\fP(1) and +\fIXsecurity\fP(__miscmansuffix__) manual pages. +.TP 8 +.B bc +disables certain kinds of error checking, for bug compatibility with +previous releases (e.g., to work around bugs in R2 and R3 xterms and toolkits). +Deprecated. +.TP 8 +.B \-bs +disables backing store support on all screens. +.TP 8 +.B \-br +sets the default root window to solid black instead of the standard root weave +pattern. +.TP 8 +.B \-c +turns off key-click. +.TP 8 +.B c \fIvolume\fP +sets key-click volume (allowable range: 0-100). +.TP 8 +.B \-cc \fIclass\fP +sets the visual class for the root window of color screens. +The class numbers are as specified in the X protocol. +Not obeyed by all servers. +.ig +.TP 8 +.B \-config \fIfilename\fP +reads more options from the given file. Options in the file may be separated +by newlines if desired. If a '#' character appears on a line, all characters +between it and the next newline are ignored, providing a simple commenting +facility. The \fB\-config\fP option itself may appear in the file. +.BR NOTE : +This option is disabled when the Xserver is run with an effective uid +different from the user's real uid. +.. +.TP 8 +.B \-core +causes the server to generate a core dump on fatal errors. +.TP 8 +.B \-displayfd \fIfd\fP +specifies a file descriptor in the launching process. Rather than specifying +a display number, the X server will attempt to listen on successively higher +display numbers, and upon finding a free one, will write the port number back +on this file descriptor as a newline-terminated string. The \fB\-pn\fR option is +ignored when using \fB\-displayfd\fR. + +nxagent specific: + +(1) Other than in X.org's Xserver, you can use \fB\-displayfd\fR in +conjunction with an explicit display number. If the explicit display number +is not available (i.e., already in use), nxagent tries to figure out the next +available display number, + +e.g.: + + \fBnxagent\fR \fI\-displayfd 2 :50\fR + +(2) If -displayfd <X> is given with <X> equaling 2 (STDERR), then the +display number string written to STDERR is beautified with some human-readable +(machine-parseable) text. +.TP 8 +.B \-deferglyphs \fIwhichfonts\fP +specifies the types of fonts for which the server should attempt to use +deferred glyph loading. \fIwhichfonts\fP can be all (all fonts), +none (no fonts), or 16 (16 bit fonts only). +.TP 8 +.B \-dpi \fIresolution\fP +sets the resolution for all screens, in dots per inch. +To be used when the server cannot determine the screen size(s) from the +hardware. +.TP 8 +.B dpms +enables DPMS (display power management services), where supported. The +default state is platform and configuration specific. +.TP 8 +.B \-dpms +disables DPMS (display power management services). The default state +is platform and configuration specific. +.TP 8 +.B \-f \fIvolume\fP +sets feep (bell) volume (allowable range: 0-100). +.TP 8 +.B \-fc \fIcursorFont\fP +sets default cursor font. +.TP 8 +.B \-fn \fIfont\fP +sets the default font. +.TP 8 +.B \-fp \fIfontPath\fP +sets the search path for fonts. This path is a comma separated list +of directories which the X server searches for font databases. +See the FONTS section of this manual page for more information and the default +list. +.TP 8 +.B \-help +prints a usage message. +.TP 8 +.B \-I +causes all remaining command line arguments to be ignored. +.TP 8 +.B \-maxbigreqsize \fIsize\fP +sets the maximum big request to +.I size +MB. +.TP 8 +.B \-nolisten \fItrans-type\fP +disables a transport type. For example, TCP/IP connections can be disabled +with +.BR "\-nolisten tcp" . +This option may be issued multiple times to disable listening to different +transport types. +.TP 8 +.B \-noreset +prevents a server reset when the last client connection is closed. This +overrides a previous +.B \-terminate +command line option. +.TP 8 +.B \-p \fIminutes\fP +sets screen-saver pattern cycle time in minutes. +.TP 8 +.B \-pn +permits the server to continue running if it fails to establish all of +its well-known sockets (connection points for clients), but +establishes at least one. This option is set by default. +.TP 8 +.B \-nopn +causes the server to exit if it fails to establish all of its well-known +sockets (connection points for clients). +.TP 8 +.B \-r +turns off auto-repeat. +.TP 8 +.B r +turns on auto-repeat. +.TP 8 +.B \-s \fIminutes\fP +sets screen-saver timeout time in minutes. +.TP 8 +.B \-su +disables save under support on all screens. +.TP 8 +.B \-t \fInumber\fP +sets pointer acceleration threshold in pixels (i.e. after how many pixels +pointer acceleration should take effect). +.TP 8 +.B \-terminate +causes the server to terminate at server reset, instead of continuing to run. +This overrides a previous +.B \-noreset +command line option. +.TP 8 +.B \-to \fIseconds\fP +sets default connection timeout in seconds. +.TP 8 +.B \-tst +disables all testing extensions. +.TP 8 +.B tty\fIxx\fP +ignored, for servers started the ancient way (from init). +.TP 8 +.B v +sets video-off screen-saver preference. +.TP 8 +.B \-v +sets video-on screen-saver preference. +.TP 8 +.B \-wm +forces the default backing-store of all windows to be WhenMapped. This +is a backdoor way of getting backing-store to apply to all windows. +Although all mapped windows will have backing store, the backing store +attribute value reported by the server for a window will be the last +value established by a client. If it has never been set by a client, +the server will report the default value, NotUseful. This behavior is +required by the X protocol, which allows the server to exceed the +client's backing store expectations but does not provide a way to tell +the client that it is doing so. +.TP 8 +.B [+-]xinerama +enables(+) or disables(-) XINERAMA provided via the PanoramiX extension. This is +set to off by default. +.TP 8 +.B [+-]rrxinerama +enables(+) or disables(-) XINERAMA provided via the RandR extension. By +default, this feature is enabled. To disable XINERAMA completely, make +sure to use both options (-xinerama -rrxinerama) on the command line. + +.SH SERVER DEPENDENT OPTIONS +\fBnxagent\fR additionally accepts the following non-standard options: +.TP 8 +.B \-logo +turns on the X Window System logo display in the screen-saver. +There is currently no way to change this from a client. +.TP 8 +.B nologo +turns off the X Window System logo display in the screen-saver. +There is currently no way to change this from a client. +.TP 8 +.B \-render + +.BR default | mono | gray | color + +sets the color allocation policy that will be used by the render extension. +.RS 8 +.TP 8 +.I default +selects the default policy defined for the display depth of the X +server. +.TP 8 +.I mono +don't use any color cell. +.TP 8 +.I gray +use a gray map of 13 color cells for the X render extension. +.TP 8 +.I color +use a color cube of at most 4*4*4 colors (that is 64 color cells). +.RE +.TP 8 +.B \-dumbSched +disables smart scheduling on platforms that support the smart scheduler. +.TP +.B \-schedInterval \fIinterval\fP +sets the smart scheduler's scheduling interval to +.I interval +milliseconds. +.SH NXAGENT SPECIFIC OPTIONS +The nx-X11 system adds the following command line arguments: +.TP 8 +.B \-forcenx +force use of NX protocol messages assuming communication through nxproxy +.TP 8 +.B \-timeout \fIint\fP +auto-disconnect timeout in seconds (minimum allowed: 60) +.TP 8 +.B \-norootlessexit +don't exit if there are no clients in rootless mode +.TP 8 +.B \-norender +disable the use of the render extension +.TP 8 +.B \-nocomposite +disable the use of the composite extension +.TP 8 +.B \-nopersistent +disable disconnection/reconnection to the X display on SIGHUP +.TP 8 +.B \-noshmem +disable use of shared memory extension +.TP 8 +.B \-shmem +enable use of shared memory extension +.TP 8 +.B \-noshpix +disable use of shared pixmaps +.TP 8 +.B \-shpix +enable use of shared pixmaps +.TP 8 +.B \-noignore +don't ignore pointer and keyboard configuration changes mandated by clients +.TP 8 +.B \-nokbreset +don't reset keyboard device if the session is resumed +.TP 8 +.B \-noxkblock +always allow applications to change layout through XKEYBOARD +.TP 8 +.B \-tile WxH +size of image tiles (minimum allowed: 32x32) +.TP 8 +.B \-D +enable desktop mode (default) +.TP 8 +.B \-R +enable rootless mode +.TP 8 +.B \-S +enable shadow mode +.TP 8 +.B \-B +enable proxy binding mode +.TP 8 +.B \-options \fIfilename\fP +path to an options file containing nx/nx options (see below). +.PP +Other than the command line options, \fBnxagent\fR can be configured at +session startup and at runtime (i.e. when resuming a suspended session) +by so-called nx/nx options. +.PP +As nx/nx options all options supported by nxcomp (see \fBnxproxy\fR man +page) and all \fBnxagent\fR nx/nx options (see below) can be used. +. +When launching an nxcomp based \fBnxagent\fR session (i.e. proxy <-> +agent), you will normally set the $DISPLAY variable like this: +.PP +.nf + $ export DISPLAY=nx/nx,listen=<proxy-port>,options=<options.file>:<nx-display-port> + $ nxagent <cmdline-options> :<nx-display-port> +.fi +.PP +The value for <nx-display-port> is some value of a not-yet-used X11 +display (e.g. :50). +.PP +Using an options file is recommended, but you can also put available +nx/nx options (see below) into the DISPLAY variable directly. Note, that +the $DISPLAY variable field is of limited length. +.PP +As <proxy-port> you can pick an arbitrary (unused) TCP port or Unix +socket file path. This is the port / socket that you have to connect to +with the \fBnxproxy\fR application. +.PP +Available \fBnxagent\fR options (as an addition to nx/nx options supported +by nxcomp already): +.TP 8 +.B options=<string> +read options from file, this text file can contain a single loooong line with comma-separated nx/nx options +.TP 8 +.B rootless=<bool> +start \fBnxagent\fR in rootless mode, matches \-R given on the command line, no-op when resuming (default: false) +.TP 8 +.B geometry=<string> +desktop geometry when starting or resuming a session, no-op in rootless mode (default 66% of the underlying X server geometry) +.TP 8 +.B resize=<bool> +set resizing support (default: true) +.TP 8 +.B fullscreen=<bool> +start or resume a session in fullscreen mode (default: off) +.TP 8 +.B keyboard=<string> +set remote keyboard layout +.TP 8 +.B clipboard=<string> + +.BR both | client | server | none + +enable / disable (set to: \fInone\fR) clipboard support, uni-directional (\fIserver\fR or \fIclient\fR) or bi-directional (\fIboth\fR, default setting) support +.TP 8 +.B streaming=<int> +streaming support for images, not fully implemented yet and thus non-functional +.TP 8 +.B backingstore=<int> +disable or enforce backing store support (default: BackingStoreUndefined) +.TP 8 +.B composite=<int> +enable or disable Compsite support in \fBnxagent\fR (default: enabled) +.TP 8 +.B xinerama=<int> +enable or disable XINERAMA support in \fBnxagent\fR (default: enabled) +.TP 8 +.B shmem=<bool> +enable using shared memory +.TP 8 +.B shpix=<bool> +enable shared pixmaps support +.TP 8 +.B kbtype=<string> +set remote keyboard type +.TP 8 +.B client=<string> +type of connecting operating system (supported: \fIlinux\fR, \fIwindows\fR, \fIsolaris\fR and \fImacosx\fR) +.TP 8 +.B shadow=<int> +start \fBnxagent\fR in shadow mode, matches \-S given on the command line, no-op when resuming (default: false) +.TP 8 +.B shadowuid=<int> +unique identifier for the shadow session +.TP 8 +.B shadowmode=<string> +full access (set to \fI1\fR) or viewing-only (set to \fI0\fR, default) +.TP 8 +.B defer=<int> +defer image updates (enabled for all connection types except LAN), accepts values \fI0\fR, \fI1\fR and \fI2\fR + +The default value can be set via the cmd line (\-defer). The value +provided as nx/nx option is set when resuming a session, thus it +overrides the cmd line default. +.TP 8 +.B tile=<string> +set the tile size in pixels (\fI<W>x<H>\fR) for bitmap data sent over the wire + +The default value can be set via the cmd line (\-tile). The value +provided as nx/nx option is set when resuming a session, thus it +overrides the cmd line default. +.TP 8 +.B menu=<int> +support pulldown menu in \fBnxagent\fR session (only available on proxy <-> agent remote sessions) +.TP 8 +.B sleep=<int> +delay X server operations when suspended (provided in msec), set to \fI0\fR to keep \fBnxagent\fR session +fully functional when suspended (e.g. useful when mirroring an \fBnxagent\fR session via VNC) +.TP 8 +.B tolerancechecks=<string> + +.BR strict|safe|risky|bypass +.RS 8 +.TP 8 +.I strict +means that the number of internal and external pixmap formats must +match exactly and every internal pixmap format must be available in the +external pixmap format array. This is the default. +.TP 8 +.I safe +means that the number of pixmap formats might diverge, but all +internal pixmap formats must also be included in the external pixmap +formats array. This is recommended, because it allows clients with more +pixmap formats to still connect, but not lose functionality. +.TP 8 +.I risky +means that the internal pixmap formats array is allowed to be +smaller than the external pixmap formats array, but at least one pixmap +format must be included in both. This is potentially unsafe. +.TP 8 +.I bypass +means that all of these checks are essentially +deactivated. This is a very bad idea. +.RE + +If you want to use \fBnxagent\fR as a replacement for Xnest or Xephyr you +can pass options like this: +.PP +.nf + $ echo nx/nx,fullscreen=1$DISPLAY >/tmp/opt + $ nxagent <cmdline-options> -options /tmp/opt :<nx-display-port> +.fi + +.SH XDMCP OPTIONS +X servers that support XDMCP have the following options. +See the \fIX Display Manager Control Protocol\fP specification for more +information. +.TP 8 +.B \-query \fIhostname\fP +enables XDMCP and sends Query packets to the specified +.IR hostname . +.TP 8 +.B \-broadcast +enable XDMCP and broadcasts BroadcastQuery packets to the network. The +first responding display manager will be chosen for the session. +.TP 8 +.B \-multicast [\fIaddress\fP [\fIhop count\fP]] +Enable XDMCP and multicast BroadcastQuery packets to the network. +The first responding display manager is chosen for the session. If an +address is specified, the multicast is sent to that address. If no +address is specified, the multicast is sent to the default XDMCP IPv6 +multicast group. If a hop count is specified, it is used as the maximum +hop count for the multicast. If no hop count is specified, the multicast +is set to a maximum of 1 hop, to prevent the multicast from being routed +beyond the local network. +.TP 8 +.B \-indirect \fIhostname\fP +enables XDMCP and send IndirectQuery packets to the specified +.IR hostname . +.TP 8 +.B \-port \fIport-number\fP +uses the specified \fIport-number\fP for XDMCP packets, instead of the +default. This option must be specified before any \-query, \-broadcast, +\-multicast, or \-indirect options. +.TP 8 +.B \-from \fIlocal-address\fP +specifies the local address to connect from (useful if the connecting host +has multiple network interfaces). The \fIlocal-address\fP may be expressed +in any form acceptable to the host platform's \fIgethostbyname\fP(3) +implementation. +.TP 8 +.B \-once +causes the server to terminate (rather than reset) when the XDMCP session +ends. +.TP 8 +.B \-class \fIdisplay-class\fP +XDMCP has an additional display qualifier used in resource lookup for +display-specific options. This option sets that value, by default it +is "MIT-Unspecified" (not a very useful value). +.TP 8 +.B \-cookie \fIxdm-auth-bits\fP +When testing XDM-AUTHENTICATION-1, a private key is shared between the +server and the manager. This option sets the value of that private +data (not that it is very private, being on the command line!). +.TP 8 +.B \-displayID \fIdisplay-id\fP +Yet another XDMCP specific value, this one allows the display manager to +identify each display so that it can locate the shared key. + +.SH XKEYBOARD OPTIONS +X servers that support the XKEYBOARD (a.k.a. \*qXKB\*q) extension accept the +following options. All layout files specified on the command line must be +located in the XKB base directory or a subdirectory, and specified as the +relative path from the XKB base directory. The default XKB base directory is +.IR /usr/share/X11/xkb . +.TP 8 +.B [+-]kb +enables(+) or disables(-) the XKEYBOARD extension. +.TP 8 +.BR [+-]accessx " [ \fItimeout\fP [ \fItimeout_mask\fP [ \fIfeedback\fP [ \fIoptions_mask\fP ] ] ] ]" +enables(+) or disables(-) AccessX key sequences. +.TP 8 +.B \-xkbdir \fIdirectory\fP +base directory for keyboard layout files. This option is not available +for setuid X servers (i.e., when the X server's real and effective uids +are different). +.TP 8 +.B \-ar1 \fImilliseconds\fP +sets the autorepeat delay (length of time in milliseconds that a key must +be depressed before autorepeat starts). +.TP 8 +.B \-ar2 \fImilliseconds\fP +sets the autorepeat interval (length of time in milliseconds that should +elapse between autorepeat-generated keystrokes). +.TP 8 +.B \-noloadxkb +disables loading of an XKB keymap description on server startup. +.TP 8 +.B \-xkbdb \fIfilename\fP +uses \fIfilename\fP for default keyboard keymaps. +.TP 8 +.B \-xkbmap \fIfilename\fP +loads keyboard description in \fIfilename\fP on server startup. + +.SH SECURITY EXTENSION OPTIONS +X servers that support the SECURITY extension accept the following option: +.TP 8 +.B \-sp \fIfilename\fP +causes the server to attempt to read and interpret filename as a security +policy file with the format described below. The file is read at server +startup and reread at each server reset. +.PP +The syntax of the security policy file is as follows. +Notation: "*" means zero or more occurrences of the preceding element, +and "+" means one or more occurrences. To interpret <foo/bar>, ignore +the text after the /; it is used to distinguish between instances of +<foo> in the next section. +.PP +.nf +<policy file> ::= <version line> <other line>* + +<version line> ::= <string/v> '\en' + +<other line > ::= <comment> | <access rule> | <site policy> | <blank line> + +<comment> ::= # <not newline>* '\en' + +<blank line> ::= <space> '\en' + +<site policy> ::= sitepolicy <string/sp> '\en' + +<access rule> ::= property <property/ar> <window> <perms> '\en' + +<property> ::= <string> + +<window> ::= any | root | <required property> + +<required property> ::= <property/rp> | <property with value> + +<property with value> ::= <property/rpv> = <string/rv> + +<perms> ::= [ <operation> | <action> | <space> ]* + +<operation> ::= r | w | d + +<action> ::= a | i | e + +<string> ::= <dbl quoted string> | <single quoted string> | <unqouted string> + +<dbl quoted string> ::= <space> " <not dqoute>* " <space> + +<single quoted string> ::= <space> ' <not squote>* ' <space> + +<unquoted string> ::= <space> <not space>+ <space> + +<space> ::= [ ' ' | '\et' ]* + +Character sets: + +<not newline> ::= any character except '\en' +<not dqoute> ::= any character except " +<not squote> ::= any character except ' +<not space> ::= any character except those in <space> +.fi +.PP +The semantics associated with the above syntax are as follows. +.PP +<version line>, the first line in the file, specifies the file format +version. If the server does not recognize the version <string/v>, it +ignores the rest of the file. The version string for the file format +described here is "version-1" . +.PP +Once past the <version line>, lines that do not match the above syntax +are ignored. +.PP +<comment> lines are ignored. +.PP +<sitepolicy> lines are currently ignored. They are intended to +specify the site policies used by the XC-QUERY-SECURITY-1 +authorization method. +.PP +<access rule> lines specify how the server should react to untrusted +client requests that affect the X Window property named <property/ar>. +The rest of this section describes the interpretation of an +<access rule>. +.PP +For an <access rule> to apply to a given instance of <property/ar>, +<property/ar> must be on a window that is in the set of windows +specified by <window>. If <window> is any, the rule applies to +<property/ar> on any window. If <window> is root, the rule applies to +<property/ar> only on root windows. +.PP +If <window> is <required property>, the following apply. If <required +property> is a <property/rp>, the rule applies when the window also +has that <property/rp>, regardless of its value. If <required +property> is a <property with value>, <property/rpv> must also have +the value specified by <string/rv>. In this case, the property must +have type STRING and format 8, and should contain one or more +null-terminated strings. If any of the strings match <string/rv>, the +rule applies. +.PP +The definition of string matching is simple case-sensitive string +comparison with one elaboration: the occurrence of the character '*' in +<string/rv> is a wildcard meaning "any string." A <string/rv> can +contain multiple wildcards anywhere in the string. For example, "x*" +matches strings that begin with x, "*x" matches strings that end with +x, "*x*" matches strings containing x, and "x*y*" matches strings that +start with x and subsequently contain y. +.PP +There may be multiple <access rule> lines for a given <property/ar>. +The rules are tested in the order that they appear in the file. The +first rule that applies is used. +.PP +<perms> specify operations that untrusted clients may attempt, and +the actions that the server should take in response to those operations. +.PP +<operation> can be r (read), w (write), or d (delete). The following +table shows how X Protocol property requests map to these operations +in The Open Group server implementation. +.PP +.nf +GetProperty r, or r and d if delete = True +ChangeProperty w +RotateProperties r and w +DeleteProperty d +ListProperties none, untrusted clients can always list all properties +.fi +.PP +<action> can be a (allow), i (ignore), or e (error). Allow means +execute the request as if it had been issued by a trusted client. +Ignore means treat the request as a no-op. In the case of +GetProperty, ignore means return an empty property value if the +property exists, regardless of its actual value. Error means do not +execute the request and return a BadAtom error with the atom set to +the property name. Error is the default action for all properties, +including those not listed in the security policy file. +.PP +An <action> applies to all <operation>s that follow it, until the next +<action> is encountered. Thus, irwad means ignore read and write, +allow delete. +.PP +GetProperty and RotateProperties may do multiple operations (r and d, +or r and w). If different actions apply to the operations, the most +severe action is applied to the whole request; there is no partial +request execution. The severity ordering is: allow < ignore < error. +Thus, if the <perms> for a property are ired (ignore read, error +delete), and an untrusted client attempts GetProperty on that property +with delete = True, an error is returned, but the property value is +not. Similarly, if any of the properties in a RotateProperties do not +allow both read and write, an error is returned without changing any +property values. +.PP +Here is an example security policy file. +.PP +.ta 3i 4i +.nf +version-1 + +# Allow reading of application resources, but not writing. +property RESOURCE_MANAGER root ar iw +property SCREEN_RESOURCES root ar iw + +# Ignore attempts to use cut buffers. Giving errors causes apps to crash, +# and allowing access may give away too much information. +property CUT_BUFFER0 root irw +property CUT_BUFFER1 root irw +property CUT_BUFFER2 root irw +property CUT_BUFFER3 root irw +property CUT_BUFFER4 root irw +property CUT_BUFFER5 root irw +property CUT_BUFFER6 root irw +property CUT_BUFFER7 root irw + +# If you are using Motif, you probably want these. +property _MOTIF_DEFAULT_BINDINGS root ar iw +property _MOTIF_DRAG_WINDOW root ar iw +property _MOTIF_DRAG_TARGETS any ar iw +property _MOTIF_DRAG_ATOMS any ar iw +property _MOTIF_DRAG_ATOM_PAIRS any ar iw + +# The next two rules let xwininfo -tree work when untrusted. +property WM_NAME any ar + +# Allow read of WM_CLASS, but only for windows with WM_NAME. +# This might be more restrictive than necessary, but demonstrates +# the <required property> facility, and is also an attempt to +# say "top level windows only." +property WM_CLASS WM_NAME ar + +# These next three let xlsclients work untrusted. Think carefully +# before including these; giving away the client machine name and command +# may be exposing too much. +property WM_STATE WM_NAME ar +property WM_CLIENT_MACHINE WM_NAME ar +property WM_COMMAND WM_NAME ar + +# To let untrusted clients use the standard colormaps created by +# xstdcmap, include these lines. +property RGB_DEFAULT_MAP root ar +property RGB_BEST_MAP root ar +property RGB_RED_MAP root ar +property RGB_GREEN_MAP root ar +property RGB_BLUE_MAP root ar +property RGB_GRAY_MAP root ar + +# To let untrusted clients use the color management database created +# by xcmsdb, include these lines. +property XDCCC_LINEAR_RGB_CORRECTION root ar +property XDCCC_LINEAR_RGB_MATRICES root ar +property XDCCC_GRAY_SCREENWHITEPOINT root ar +property XDCCC_GRAY_CORRECTION root ar + +# To let untrusted clients use the overlay visuals that many vendors +# support, include this line. +property SERVER_OVERLAY_VISUALS root ar + +# Dumb examples to show other capabilities. + +# oddball property names and explicit specification of error conditions +property "property with spaces" 'property with "' aw er ed + +# Allow deletion of Woo-Hoo if window also has property OhBoy with value +# ending in "son". Reads and writes will cause an error. +property Woo-Hoo OhBoy = "*son" ad + +.fi +.SH "NETWORK CONNECTIONS" +The X server supports client connections via a platform-dependent subset of +the following transport types: TCP\/IP, Unix Domain sockets +and several varieties of SVR4 local connections. See the DISPLAY +NAMES section of the \fIX\fP(__miscmansuffix__) manual page to learn how to +specify which transport type clients should try to use. + +.SH GRANTING ACCESS +The X server implements a platform-dependent subset of the following +authorization protocols: MIT-MAGIC-COOKIE-1, XDM-AUTHORIZATION-1, +XDM-AUTHORIZATION-2, SUN-DES-1, and MIT-KERBEROS-5. See the +\fIXsecurity\fP(__miscmansuffix__) manual page for information on the +operation of these protocols. +.PP +Authorization data required by the above protocols is passed to the +server in a private file named with the \fB\-auth\fP command line +option. Each time the server is about to accept the first connection +after a reset (or when the server is starting), it reads this file. +If this file contains any authorization records, the local host is not +automatically allowed access to the server, and only clients which +send one of the authorization records contained in the file in the +connection setup information will be allowed access. See the +\fIXau\fP manual page for a description of the binary format of this +file. See \fIxauth\fP(1) for maintenance of this file, and distribution +of its contents to remote hosts. +.PP +The X server also uses a host-based access control list for deciding +whether or not to accept connections from clients on a particular machine. +If no other authorization mechanism is being used, +this list initially consists of the host on which the server is running as +well as any machines listed in the file \fI/etc/X\fBn\fI.hosts\fR, where +\fBn\fP is the display number of the server. Each line of the file should +contain either an Internet hostname (e.g. expo.lcs.mit.edu) or a complete +name in the format \fIfamily\fP:\fIname\fP as described in the +\fIxhost\fP(1) manual page. +There should be no leading or trailing spaces on any lines. For example: +.sp +.in +8 +.nf +joesworkstation +corporate.company.com +star:: +inet:bigcpu +local: +.fi +.in -8 +.PP +Users can add or remove hosts from this list and enable or disable access +control using the \fIxhost\fP command from the same machine as the server. +.PP +If the X FireWall Proxy (\fIxfwp\fP) is being used without a sitepolicy, +host-based authorization must be turned on for clients to be able to +connect to the X server via the \fIxfwp\fP. If \fIxfwp\fP is run without +a configuration file and thus no sitepolicy is defined, if \fIxfwp\fP +is using an X server where xhost + has been run to turn off host-based +authorization checks, when a client tries to connect to this X server +via \fIxfwp\fP, the X server will deny the connection. See \fIxfwp\fP(1) +for more information about this proxy. +.PP +The X protocol intrinsically does not have any notion of window operation +permissions or place any restrictions on what a client can do; if a program can +connect to a display, it has full run of the screen. +X servers that support the SECURITY extension fare better because clients +can be designated untrusted via the authorization they use to connect; see +the \fIxauth\fP(1) manual page for details. Restrictions are imposed +on untrusted clients that curtail the mischief they can do. See the SECURITY +extension specification for a complete list of these restrictions. +.PP +Sites that have better +authentication and authorization systems might wish to make +use of the hooks in the libraries and the server to provide additional +security models. +.SH SIGNALS +The X server attaches special meaning to the following signals: +.TP 8 +.I SIGHUP +This signal causes the server to close all existing connections, free all +resources, and restore all defaults. It is sent by the display manager +whenever the main user's main application (usually an \fIxterm\fP or window +manager) exits to force the server to clean up and prepare for the next +user. +.TP 8 +.I SIGTERM +This signal causes the server to exit cleanly. +.TP 8 +.I SIGUSR1 +This signal is used quite differently from either of the above. When the +server starts, it checks to see if it has inherited SIGUSR1 as SIG_IGN +instead of the usual SIG_DFL. In this case, the server sends a SIGUSR1 to +its parent process after it has set up the various connection schemes. +\fIXdm\fP uses this feature to recognize when connecting to the server +is possible. +.SH FONTS +The X server +can obtain fonts from directories and/or from font servers. +The list of directories and font servers +the X server uses when trying to open a font is controlled +by the \fIfont path\fP. +.LP +The default font path is +__default_font_path__ . +.LP +The font path can be set with the \fB\-fp\fP option or by \fIxset\fP(1) +after the server has started. +.SH FILES +.TP 30 +.I /etc/X\fBn\fP.hosts +Initial access control list for display number \fBn\fP +.TP 30 +.IR /usr/share/fonts/X11/misc, + /usr/share/fonts/X11/75dpi, + /usr/share/fonts/X11/100dpi +Bitmap font directories +.TP 30 +.IR /usr/share/fonts/X11/Type1 +Outline font directories +.TP 30 +.I /usr/share/nx/rgb +Color database +.TP 30 +.I /tmp/.X11-unix/X\fBn\fP +Unix domain socket for display number \fBn\fP +.TP 30 +.IR /tmp/rcX\fBn\fP +Kerberos 5 replay cache for display number \fBn\fP +.SH "SEE ALSO" +Protocols: +.I "X Window System Protocol," +.I "NX Compression Protocol," +.I "The X Font Service Protocol," +.I "X Display Manager Control Protocol" +.PP +Fonts: \fIbdftopcf\fP(1), \fImkfontdir\fP(1), \fImkfontscale\fP(1), +\fIxfs\fP(1), \fIxlsfonts\fP(1), \fIxfontsel\fP(1), \fIxfd\fP(1), +.I "X Logical Font Description Conventions" +.PP +Security: \fIXsecurity\fP(__miscmansuffix__), \fIxauth\fP(1), \fIXau\fP(1), +\fIxdm\fP(1), \fIxhost\fP(1), \fIxfwp\fP(1), +.I "Security Extension Specification" +.PP +Starting the server: \fIxdm\fP(1), \fIxinit\fP(1) +.PP +Controlling the server once started: \fIxset\fP(1), \fIxsetroot\fP(1), +\fIxhost\fP(1) +.PP +Server-specific man pages: +\fIXdec\fP(1), \fIXmacII\fP(1), \fIXsun\fP(1), \fIXnest\fP(1), +\fIXvfb\fP(1), \fIXFree86\fP(1), \fIXDarwin\fP(1). +.PP +Server internal documentation: +.I "Definition of the Porting Layer for the X v11 Sample Server" +.SH AUTHORS +The first sample X server was originally written by Susan Angebranndt, +Raymond Drewry, Philip Karlton, and Todd Newman, from Digital Equipment +Corporation, with support from a large cast. It has since been +extensively rewritten by Keith Packard and Bob Scheifler, from MIT. Dave +Wiggins took over post-R5 and made substantial improvements. +.PP +The first implementation of nx-X11 (version 1.x up to 3.5.x) was written +by NoMachine (maintained until 2011). +.PP +The current implementation of nx-X11 is maintained by various projects, +amongst others The Arctica Project, TheQVD (Qindel Group) and X2Go. +.PP +This manual page was written by Per Hansen <spamhans@yahoo.de>, and +modified by Marcelo Boveto Shima <marceloshima@gmail.com> and Mike +Gabriel <mike.gabriel@das-netzwerkteam.de>. In 2016, the original +Xserver.man page shipped with nx-X11 was merged into the \fBnxagent\fR +man page and received a major update by Mike Gabriel +<mike.gabriel@das-netzwerkteam.de>. + diff --git a/nx-X11/programs/Xserver/hw/nxagent/nxagent.xpm b/nx-X11/programs/Xserver/hw/nxagent/nxagent.xpm new file mode 100644 index 000000000..bcdaa2204 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/nxagent.xpm @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* XPM */ +static char *nxagentIconData[] = { +"16 16 5 1", +" c None", +"! c black", +"# c #FF0000", +"$ c #424242", +"% c #750202", +" ", +"############### ", +"# #$", +"# #% #######% #$", +"# #% #%%#%%#% #$", +"# #% #% #% #% #$", +"# #% #% #% #% #$", +"# #% #% #% #% #$", +"# %% #% #% #% #$", +"# #% #% #% #$", +"# #% #% #% #% #$", +"# %% %% %% %% #$", +"# #$", +"###############$", +" $$$$$$$$$$$$$$$", +" "}; diff --git a/nx-X11/programs/Xserver/hw/nxagent/nxmissing.xpm b/nx-X11/programs/Xserver/hw/nxagent/nxmissing.xpm new file mode 100644 index 000000000..3fb4362d1 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/nxmissing.xpm @@ -0,0 +1,56 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +static char *placeholderXpm[] = { +/* columns rows colors chars-per-pixel */ +"14 16 10 1", +" c #000000", +". c #0000FF", +"X c #008400", +"o c #00FF00", +"O c #00FFFF", +"+ c #FF0000", +"@ c #FF00FF", +"# c #848484", +"$ c #BDBDBD", +"% c #FFFFFF", +/* pixels */ +" #%%%", +" %%%%%%%%%##%%", +" %$$$$$$$$#%#%", +" %$$$XX$$$#%%#", +" %$$XoX $$ ", +" %$$XXX $$$$% ", +" %$$$ $$$$$% ", +" %$$$$$$... % ", +" %$+$$$$.O. % ", +" %$@+$$$... % ", +" %$@@+$$ $% ", +" %$@@@+$$$$$% ", +" %$ +$$$$% ", +" %$$$$$$$$$$% ", +" %%%%%%%%%%%% ", +" " +}; diff --git a/nx-X11/programs/Xserver/hw/nxagent/screensaver b/nx-X11/programs/Xserver/hw/nxagent/screensaver new file mode 100644 index 000000000..a9ca85114 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/screensaver @@ -0,0 +1,711 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#define screensaver_width 256 +#define screensaver_height 256 +static unsigned char screensaver_bits[] = { + 0xa8, 0x00, 0xa0, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, + 0x00, 0x00, 0x00, 0xa8, 0xaa, 0x02, 0x00, 0x80, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x40, 0x55, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x55, 0x05, 0x00, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x80, 0xaa, 0x2a, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xaa, 0x02, 0x00, 0xa0, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x50, 0x55, 0x05, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0xaa, + 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0xa0, + 0xaa, 0x0a, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x15, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xaa, 0x2a, 0x80, 0x02, 0x80, 0xaa, 0xaa, 0x82, 0x0a, 0xa8, 0x28, 0x80, + 0x8a, 0x80, 0x2a, 0x80, 0x80, 0x8a, 0xa2, 0x82, 0x0a, 0xaa, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x80, 0x82, 0x41, 0x40, 0x00, 0x50, + 0x55, 0x41, 0x00, 0x00, 0x04, 0x00, 0x54, 0x40, 0x10, 0x00, 0x40, 0x00, + 0x51, 0x55, 0x00, 0x15, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0xa8, 0x8a, 0x02, 0x00, 0x02, + 0x00, 0x20, 0xa2, 0x00, 0x80, 0x00, 0x08, 0x00, 0xaa, 0x2a, 0x00, 0x2a, + 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x80, + 0x01, 0x00, 0x01, 0x50, 0x45, 0x05, 0x00, 0x01, 0x10, 0x10, 0x40, 0x11, + 0x40, 0x00, 0x44, 0x00, 0x50, 0x15, 0x01, 0x15, 0x04, 0x00, 0x40, 0x00, + 0x05, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x50, 0x20, 0x00, 0x00, 0xa2, + 0xaa, 0x2a, 0x00, 0x00, 0x02, 0x00, 0xa0, 0x08, 0x00, 0x00, 0x00, 0x00, + 0xa2, 0xaa, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x01, 0x40, 0x44, 0x15, 0x10, 0x01, + 0x10, 0x10, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x54, 0x55, 0x41, 0x45, + 0x04, 0x00, 0x40, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x54, + 0x20, 0x80, 0x00, 0x82, 0xaa, 0x0a, 0x00, 0x00, 0x22, 0x00, 0x80, 0x0a, + 0x00, 0x00, 0x82, 0x00, 0xa0, 0x8a, 0x22, 0x02, 0x00, 0x08, 0x20, 0x00, + 0xa8, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x2a, 0x10, 0x40, 0x00, 0x01, + 0x54, 0x45, 0x10, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00, + 0x50, 0x45, 0x05, 0x41, 0x00, 0x04, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0xaa, 0xaa, 0x0a, 0x0a, 0x00, + 0x20, 0x08, 0x00, 0x20, 0x00, 0x00, 0x80, 0x00, 0xa8, 0xa2, 0x22, 0x2a, + 0x00, 0x00, 0x0a, 0x00, 0xa8, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x0a, + 0x50, 0x05, 0x00, 0x01, 0x55, 0x45, 0x00, 0x00, 0x01, 0x00, 0x00, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x55, 0x11, 0x00, 0x00, 0x54, 0x01, 0x00, + 0x44, 0x01, 0x00, 0x00, 0x05, 0x40, 0x00, 0x05, 0x00, 0x08, 0x00, 0x80, + 0xaa, 0xaa, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x80, 0x00, + 0x80, 0xaa, 0x28, 0x20, 0x00, 0x00, 0x02, 0x00, 0x80, 0x02, 0x00, 0x00, + 0x28, 0x00, 0x80, 0x02, 0x10, 0x10, 0x00, 0x01, 0x54, 0x45, 0x01, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x10, 0x55, 0x14, 0x00, + 0x00, 0x04, 0x04, 0x00, 0x40, 0x01, 0x00, 0x00, 0x40, 0x40, 0x40, 0x01, + 0x08, 0x00, 0x80, 0x00, 0xa8, 0xa2, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x20, 0xa0, 0xaa, 0x00, 0x80, 0x28, 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x80, 0x02, 0x00, 0x00, 0x80, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x14, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x40, 0x00, 0x00, 0x08, 0x20, 0x80, 0x00, 0x08, 0x08, 0x80, 0x80, + 0x80, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x8a, 0x00, + 0x02, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, + 0x10, 0x10, 0x00, 0x01, 0x10, 0x45, 0x55, 0x01, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, + 0x20, 0xa2, 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x80, 0x00, 0x02, 0x04, 0x00, 0x40, 0x00, 0x04, 0x04, 0x40, 0x40, + 0x00, 0x01, 0x00, 0x04, 0x04, 0x00, 0x00, 0x01, 0x00, 0x51, 0x45, 0x05, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x45, 0x01, + 0x2a, 0x80, 0xaa, 0xaa, 0x82, 0xaa, 0x2a, 0xa0, 0x02, 0x02, 0x80, 0xa8, + 0x00, 0x2a, 0xa0, 0x02, 0x80, 0xa2, 0x00, 0xa0, 0xa0, 0x0a, 0xa0, 0x00, + 0x00, 0x00, 0x80, 0x88, 0x02, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x41, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xa0, 0xaa, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x40, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x80, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, + 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x55, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x05, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x54, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x15, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xa8, 0xaa, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x50, 0x55, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x15, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, + 0x00, 0x00, 0xa8, 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x2a, 0x20, 0x00, 0x00, 0x41, 0x05, 0x55, 0x54, 0x11, 0x04, 0x00, 0x14, + 0x40, 0x10, 0x44, 0x15, 0x15, 0x00, 0x00, 0x50, 0x01, 0x00, 0x50, 0x55, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x10, 0x50, 0x40, + 0x82, 0x08, 0x02, 0x08, 0x20, 0x08, 0x00, 0x22, 0xa0, 0x20, 0x88, 0x00, + 0x22, 0x00, 0x00, 0xa8, 0x2a, 0x00, 0xa0, 0xaa, 0x0a, 0x00, 0x80, 0x02, + 0x00, 0x00, 0x00, 0x00, 0xaa, 0x08, 0x88, 0x20, 0x44, 0x10, 0x01, 0x04, + 0x50, 0x04, 0x00, 0x41, 0x10, 0x11, 0x44, 0x00, 0x41, 0x00, 0x00, 0x54, + 0x41, 0x00, 0x40, 0x55, 0x15, 0x00, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x11, 0x04, 0x11, 0x80, 0x20, 0x02, 0x08, 0xa0, 0x08, 0x00, 0x02, + 0x88, 0x20, 0x88, 0x00, 0x82, 0x00, 0x00, 0x2a, 0x22, 0x00, 0x80, 0xaa, + 0x2a, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x08, 0x20, + 0x40, 0x10, 0x01, 0x04, 0x50, 0x04, 0x00, 0x01, 0x04, 0x41, 0x44, 0x00, + 0x41, 0x00, 0x00, 0x15, 0x05, 0x14, 0x15, 0x50, 0x10, 0x05, 0x40, 0x41, + 0x41, 0x10, 0x45, 0x05, 0x50, 0x04, 0x04, 0x10, 0x80, 0x20, 0x02, 0x08, + 0xa0, 0x08, 0x00, 0x02, 0x08, 0x22, 0x82, 0x00, 0x82, 0x00, 0x00, 0x0a, + 0x2a, 0x22, 0x8a, 0x22, 0x22, 0x08, 0x80, 0x22, 0x22, 0x88, 0x88, 0x02, + 0x28, 0x02, 0x08, 0x20, 0x40, 0x10, 0x15, 0x54, 0x10, 0x05, 0x00, 0x14, + 0x04, 0x41, 0x44, 0x05, 0x41, 0x00, 0x00, 0x05, 0x50, 0x01, 0x41, 0x04, + 0x05, 0x11, 0x00, 0x05, 0x44, 0x44, 0x50, 0x00, 0x10, 0x05, 0x50, 0x10, + 0x80, 0x0a, 0x02, 0x08, 0x20, 0x0a, 0x00, 0x20, 0xa8, 0x82, 0x82, 0x00, + 0x2a, 0x00, 0x80, 0x02, 0x22, 0x02, 0x82, 0x20, 0x20, 0x08, 0x20, 0x88, + 0x82, 0x88, 0x8a, 0x00, 0x88, 0x0a, 0x80, 0x20, 0x40, 0x04, 0x01, 0x04, + 0x10, 0x05, 0x00, 0x40, 0x04, 0x41, 0x41, 0x00, 0x11, 0x00, 0x40, 0x01, + 0x41, 0x41, 0x41, 0x14, 0x15, 0x11, 0x40, 0x44, 0x04, 0x44, 0x40, 0x00, + 0x44, 0x15, 0x00, 0x11, 0x80, 0x08, 0x02, 0x08, 0x20, 0x0a, 0x00, 0x80, + 0x08, 0x82, 0x82, 0x00, 0x22, 0x00, 0xa0, 0x00, 0x22, 0x22, 0x82, 0x20, + 0x22, 0x0a, 0x20, 0x28, 0x82, 0x82, 0x88, 0x00, 0x88, 0x2a, 0x00, 0x22, + 0x44, 0x10, 0x01, 0x04, 0x10, 0x04, 0x00, 0x41, 0x04, 0x01, 0x41, 0x00, + 0x41, 0x00, 0x50, 0x01, 0x14, 0x14, 0x01, 0x55, 0x10, 0x15, 0x40, 0x45, + 0x05, 0x01, 0x45, 0x00, 0x04, 0x55, 0x04, 0x11, 0x82, 0x20, 0x02, 0x08, + 0x20, 0x08, 0x00, 0x22, 0x08, 0x82, 0x80, 0x00, 0x82, 0x00, 0xa8, 0x00, + 0x00, 0x00, 0x00, 0xa0, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xaa, 0x88, 0x20, 0x41, 0x10, 0x55, 0x54, 0x11, 0x04, 0x00, 0x14, + 0x04, 0x01, 0x41, 0x15, 0x41, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x54, 0x51, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0x2a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x54, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xaa, 0x02, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xa8, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0xa0, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x15, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x40, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x80, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x14, 0x40, 0x01, 0x41, 0x40, 0x01, 0x14, 0x10, 0x01, 0x00, 0x40, + 0x01, 0x04, 0x14, 0x14, 0x14, 0x10, 0x04, 0x00, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0xaa, 0x00, 0x00, 0x00, 0x80, 0x82, 0xa0, 0x20, 0x82, + 0xa2, 0x20, 0x02, 0x22, 0x28, 0x02, 0x00, 0x08, 0x8a, 0x22, 0x08, 0x08, + 0x22, 0x28, 0x0a, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, + 0x01, 0x00, 0x00, 0x40, 0x41, 0x40, 0x10, 0x04, 0x11, 0x11, 0x04, 0x41, + 0x10, 0x04, 0x00, 0x04, 0x04, 0x40, 0x10, 0x00, 0x41, 0x10, 0x11, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xaa, 0x02, 0x00, 0x00, 0xa0, + 0x82, 0x80, 0x08, 0x08, 0x02, 0x08, 0x88, 0x80, 0x08, 0x08, 0x00, 0x08, + 0x08, 0x20, 0x20, 0x80, 0x80, 0x20, 0x00, 0x00, 0x10, 0x50, 0x14, 0x14, + 0x45, 0x05, 0x40, 0x05, 0x41, 0x14, 0x15, 0x50, 0x41, 0x01, 0x04, 0x00, + 0x01, 0x04, 0x50, 0x00, 0x11, 0x04, 0x00, 0x14, 0x00, 0x40, 0x10, 0x44, + 0x00, 0x11, 0x00, 0x00, 0xa0, 0x88, 0x22, 0xa2, 0x88, 0x08, 0x00, 0x2a, + 0x82, 0x22, 0x22, 0xa8, 0x80, 0x0a, 0x08, 0x00, 0x02, 0xa8, 0x8a, 0xaa, + 0x08, 0x08, 0x00, 0xa8, 0x00, 0x2a, 0x20, 0x80, 0xaa, 0x20, 0x00, 0x00, + 0x00, 0x05, 0x04, 0x15, 0x55, 0x04, 0x40, 0x04, 0x50, 0x54, 0x01, 0x54, + 0x00, 0x54, 0x04, 0x00, 0x01, 0x04, 0x40, 0x00, 0x10, 0x04, 0x00, 0x40, + 0x05, 0x41, 0x40, 0x40, 0x00, 0x10, 0x00, 0x00, 0x80, 0x08, 0x02, 0x82, + 0x80, 0x08, 0x80, 0x20, 0x02, 0x02, 0x02, 0x2a, 0x00, 0xa0, 0x08, 0x00, + 0x02, 0x08, 0x80, 0x00, 0x08, 0x08, 0x00, 0x00, 0x8a, 0x20, 0x20, 0x82, + 0x00, 0x20, 0x00, 0x00, 0x10, 0x45, 0x04, 0x11, 0x51, 0x04, 0x50, 0x44, + 0x44, 0x44, 0x01, 0x15, 0x00, 0x40, 0x05, 0x00, 0x01, 0x04, 0x40, 0x00, + 0x10, 0x04, 0x00, 0x00, 0x54, 0x40, 0x40, 0x41, 0x00, 0x10, 0x00, 0x00, + 0xa0, 0x28, 0x02, 0x0a, 0x8a, 0x08, 0x20, 0x0a, 0x0a, 0x28, 0x02, 0x0a, + 0x00, 0x80, 0x08, 0x00, 0x02, 0x08, 0x80, 0x00, 0x08, 0x08, 0x00, 0x00, + 0x88, 0x20, 0x80, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x05, 0x40, 0x00, 0x11, 0x00, + 0x01, 0x10, 0x10, 0x01, 0x11, 0x04, 0x00, 0x04, 0x50, 0x40, 0x41, 0x01, + 0x01, 0x11, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, + 0xaa, 0x00, 0x80, 0x02, 0x80, 0x80, 0x20, 0x02, 0x02, 0x20, 0x08, 0x82, + 0x08, 0x08, 0x00, 0x08, 0x88, 0x20, 0x80, 0x00, 0x82, 0x20, 0x00, 0x00, + 0x00, 0x40, 0x01, 0x10, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x40, 0x01, + 0x40, 0x14, 0x40, 0x41, 0x05, 0x40, 0x01, 0x14, 0x14, 0x14, 0x00, 0x44, + 0x01, 0x45, 0x00, 0x00, 0x14, 0x54, 0x00, 0x00, 0x00, 0x80, 0x02, 0x08, + 0x00, 0x00, 0x00, 0xa8, 0xaa, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x04, 0x00, 0x00, 0x00, 0x50, + 0x55, 0x05, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x02, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0x0a, 0xa8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, + 0x00, 0x00, 0x00, 0x50, 0x55, 0x05, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0xa0, + 0xaa, 0x0a, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x15, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xaa, 0x2a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x15, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x8a, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x02, 0x00, 0x00, 0x00, 0x00, + 0xa8, 0xa2, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x05, 0x50, 0x00, 0x50, 0x40, 0x45, 0x11, 0x00, 0x50, + 0x40, 0x41, 0x01, 0x00, 0x14, 0x00, 0x51, 0x40, 0x40, 0x00, 0x05, 0x14, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0a, + 0x88, 0x02, 0xaa, 0xa8, 0x80, 0x00, 0x00, 0xaa, 0xa8, 0xa2, 0x02, 0x00, + 0xa2, 0xa0, 0x22, 0xa8, 0xa0, 0xa0, 0x8a, 0x2a, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x14, 0x04, 0x01, 0x45, 0x51, + 0x04, 0x40, 0x00, 0x45, 0x41, 0x51, 0x01, 0x00, 0x41, 0x50, 0x54, 0x50, + 0x50, 0x50, 0x14, 0x14, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x82, 0xa2, 0xa0, 0x02, 0xa0, 0x88, 0x82, + 0xa0, 0x88, 0x02, 0x80, 0x82, 0x28, 0x28, 0xa0, 0x20, 0x28, 0x08, 0x8a, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x45, 0x54, 0x00, + 0x14, 0x40, 0x41, 0x50, 0x05, 0x51, 0x10, 0x41, 0x41, 0x41, 0x01, 0x00, + 0x05, 0x14, 0x10, 0x50, 0x40, 0x10, 0x14, 0x54, 0x04, 0x00, 0x41, 0x55, + 0x04, 0x45, 0x01, 0x04, 0x20, 0x02, 0x08, 0x00, 0x2a, 0xa0, 0x00, 0xa0, + 0x8a, 0x20, 0xa8, 0xa2, 0xa0, 0xa0, 0x00, 0x80, 0x0a, 0x28, 0x28, 0xa0, + 0x20, 0x28, 0x0a, 0x2a, 0x00, 0x00, 0x22, 0x0a, 0x80, 0x88, 0x02, 0x88, + 0x04, 0x50, 0x01, 0x00, 0x54, 0x40, 0x01, 0x50, 0x15, 0x10, 0x14, 0x51, + 0x40, 0x41, 0x01, 0x00, 0x15, 0x14, 0x14, 0x40, 0x11, 0x14, 0x05, 0x14, + 0x00, 0x40, 0x10, 0x00, 0x15, 0x45, 0x04, 0x01, 0x00, 0x00, 0x08, 0x00, + 0xa8, 0xa0, 0x00, 0x28, 0x8a, 0x08, 0x0a, 0x28, 0xa0, 0xa0, 0x00, 0x00, + 0x2a, 0x0a, 0x28, 0xa0, 0x08, 0x8a, 0x02, 0x0a, 0x00, 0x80, 0x00, 0x08, + 0x80, 0x00, 0x00, 0x82, 0x44, 0x11, 0x00, 0x00, 0x50, 0x50, 0x00, 0x10, + 0x05, 0x40, 0x15, 0x05, 0x50, 0x50, 0x00, 0x00, 0x14, 0x14, 0x14, 0x40, + 0x11, 0x54, 0x00, 0x05, 0x00, 0x00, 0x11, 0x00, 0x01, 0x40, 0x04, 0x44, + 0x80, 0x20, 0x0a, 0x00, 0xa0, 0xa0, 0x00, 0x88, 0x82, 0xa8, 0x0a, 0x00, + 0xa0, 0xa0, 0x00, 0x00, 0x28, 0x0a, 0x0a, 0xa0, 0x08, 0x0a, 0x00, 0x0a, + 0x00, 0x00, 0x22, 0x0a, 0xa2, 0x00, 0x00, 0x88, 0x01, 0x40, 0x15, 0x00, + 0x50, 0x51, 0x40, 0x00, 0x01, 0x51, 0x15, 0x00, 0x50, 0x50, 0x00, 0x00, + 0x54, 0x14, 0x54, 0x40, 0x05, 0x14, 0x00, 0x05, 0x00, 0x40, 0x41, 0x15, + 0x14, 0x45, 0x04, 0x05, 0x00, 0x00, 0x00, 0x80, 0xa0, 0xa0, 0x20, 0x88, + 0x80, 0xaa, 0x08, 0x82, 0x28, 0x28, 0x02, 0x20, 0x28, 0x0a, 0x2a, 0xa0, + 0x02, 0x0a, 0x88, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x40, 0x11, 0x44, 0x00, 0x55, 0x14, 0x44, + 0x50, 0x50, 0x01, 0x40, 0x10, 0x54, 0x15, 0x40, 0x01, 0x14, 0x04, 0x45, + 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x22, 0xa0, 0x0a, 0x00, 0x00, 0x0a, 0x2a, 0x20, 0x28, 0xa8, 0x00, 0xa0, + 0x08, 0xa8, 0x08, 0xa0, 0x00, 0xa8, 0x82, 0x82, 0x02, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x05, 0x00, + 0x00, 0x54, 0x55, 0x10, 0x50, 0x50, 0x00, 0x00, 0x05, 0x50, 0x04, 0x40, + 0x00, 0x50, 0x40, 0x05, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x80, 0xaa, 0x2a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x40, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0a, + 0x00, 0x80, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x00, 0x00, 0x55, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xa0, 0x02, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, + 0x00, 0x00, 0x54, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa8, 0xaa, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x50, 0x55, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0xa0, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x50, 0x55, + 0x05, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0x0a, 0x00, 0x00, 0x28, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x40, 0x55, 0x15, 0x00, 0x00, 0x50, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0a, 0x00, 0x00, 0x00, 0x80, 0xaa, + 0x2a, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x55, 0x50, 0x15, + 0x55, 0x11, 0x55, 0x00, 0x15, 0x00, 0x54, 0x01, 0x00, 0x54, 0x01, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x00, 0x20, 0x82, 0x20, 0x08, 0x82, 0x00, 0x22, 0x80, + 0x08, 0x08, 0x28, 0xa2, 0x28, 0x20, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xa2, + 0x00, 0x04, 0x41, 0x10, 0x04, 0x11, 0x00, 0x40, 0x10, 0x14, 0x10, 0x54, + 0x54, 0x11, 0x10, 0x00, 0x01, 0x00, 0x50, 0x14, 0x15, 0x05, 0x45, 0x01, + 0x50, 0x50, 0x44, 0x14, 0x05, 0x00, 0x04, 0x40, 0x20, 0x02, 0x22, 0x02, + 0x22, 0x08, 0x20, 0x20, 0x00, 0x08, 0x20, 0xa8, 0x28, 0x22, 0x08, 0x80, + 0x02, 0x00, 0x88, 0x22, 0xa2, 0x88, 0x28, 0x02, 0x88, 0x80, 0x22, 0xa2, + 0x08, 0x00, 0x08, 0x22, 0x00, 0x04, 0x41, 0x00, 0x04, 0x00, 0x01, 0x40, + 0x00, 0x10, 0x40, 0x04, 0x11, 0x10, 0x04, 0x10, 0x05, 0x00, 0x10, 0x04, + 0x01, 0x55, 0x45, 0x04, 0x10, 0x50, 0x44, 0x15, 0x01, 0x00, 0x14, 0x10, + 0x00, 0x2a, 0xa0, 0x02, 0x2a, 0x20, 0x22, 0x80, 0x02, 0x22, 0x20, 0x02, + 0x0a, 0xa0, 0x02, 0x08, 0x0a, 0x00, 0x20, 0x02, 0x82, 0x80, 0x20, 0x02, + 0x80, 0x88, 0x28, 0x82, 0x00, 0x00, 0xa8, 0x20, 0x00, 0x44, 0x40, 0x01, + 0x14, 0x00, 0x04, 0x00, 0x05, 0x10, 0x40, 0x00, 0x11, 0x10, 0x05, 0x04, + 0x14, 0x00, 0x44, 0x44, 0x01, 0x51, 0x44, 0x04, 0x10, 0x45, 0x14, 0x11, + 0x01, 0x00, 0x50, 0x11, 0x00, 0x82, 0x20, 0x02, 0x22, 0x20, 0x28, 0x20, + 0x08, 0x2a, 0x80, 0x02, 0x02, 0x20, 0x08, 0x00, 0x00, 0x00, 0x28, 0x28, + 0x02, 0x8a, 0x22, 0x02, 0xa0, 0xa8, 0x08, 0x8a, 0x00, 0x00, 0x80, 0x22, + 0x00, 0x04, 0x41, 0x10, 0x04, 0x01, 0x10, 0x00, 0x10, 0x41, 0x40, 0x01, + 0x11, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x51, 0x20, 0x82, 0x20, 0x00, + 0x02, 0x20, 0x28, 0x20, 0x88, 0x20, 0x80, 0x00, 0x82, 0x20, 0x28, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x10, 0x04, 0x45, 0x10, 0x04, 0x01, 0x10, 0x40, + 0x04, 0x40, 0x00, 0x00, 0x41, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x41, + 0x8a, 0x0a, 0xaa, 0x8a, 0xaa, 0xa8, 0x20, 0xa0, 0x82, 0xa2, 0x80, 0x80, + 0xaa, 0xa8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xa8, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xa0, 0xa2, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x2a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x10, 0x50, + 0x41, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x15, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xa0, 0x80, 0x02, 0xa8, 0x28, + 0x0a, 0xa0, 0x02, 0xa8, 0x00, 0x8a, 0x02, 0x28, 0x00, 0x00, 0x00, 0x0a, + 0x28, 0x80, 0x2a, 0x80, 0x22, 0x80, 0x0a, 0x00, 0xa8, 0x00, 0x28, 0x2a, + 0x00, 0x05, 0x00, 0x50, 0x00, 0x00, 0x55, 0x51, 0x14, 0x14, 0x54, 0x54, + 0x01, 0x54, 0x01, 0x50, 0x50, 0x05, 0x00, 0x05, 0x00, 0x50, 0x55, 0x40, + 0x51, 0x50, 0x15, 0x00, 0x54, 0x05, 0x14, 0x55, 0x00, 0x0a, 0x00, 0xa0, + 0x00, 0x80, 0xaa, 0x2a, 0x2a, 0x08, 0x2a, 0xa8, 0x02, 0xaa, 0x02, 0xa0, + 0xa0, 0x02, 0x00, 0x0a, 0x00, 0xa8, 0xaa, 0x80, 0x2a, 0xa8, 0x2a, 0x80, + 0xaa, 0x0a, 0xa8, 0xaa, 0x01, 0x05, 0x00, 0x50, 0x05, 0x40, 0x55, 0x55, + 0x14, 0x00, 0x14, 0x50, 0x05, 0x54, 0x01, 0x40, 0x51, 0x01, 0x00, 0x55, + 0x00, 0x54, 0x55, 0x41, 0x15, 0x54, 0x55, 0x40, 0x55, 0x15, 0x54, 0x55, + 0x02, 0x0a, 0x00, 0xa0, 0x0a, 0xa0, 0x02, 0x2a, 0x2a, 0x00, 0x0a, 0x88, + 0x0a, 0x2a, 0x00, 0x80, 0xaa, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0xa0, 0xa2, + 0x0a, 0x2a, 0xa8, 0xa0, 0x0a, 0x0a, 0xaa, 0xa0, 0x01, 0x14, 0x01, 0x40, + 0x55, 0x50, 0x01, 0x14, 0x14, 0x00, 0x05, 0x04, 0x15, 0x15, 0x00, 0x00, + 0x51, 0x00, 0x00, 0x54, 0x05, 0x14, 0x40, 0x45, 0x05, 0x15, 0x50, 0x41, + 0x01, 0x14, 0x54, 0x40, 0x02, 0xa8, 0x00, 0x80, 0xaa, 0xa8, 0x00, 0x2a, + 0x28, 0x88, 0x02, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, + 0x0a, 0x0a, 0xa0, 0xa2, 0x82, 0x0a, 0xa0, 0xa0, 0x00, 0x28, 0x2a, 0xa0, + 0x01, 0x50, 0x00, 0x00, 0x55, 0x50, 0x00, 0x14, 0x54, 0x54, 0x05, 0x15, + 0x14, 0x15, 0x00, 0x00, 0x11, 0x00, 0x00, 0x50, 0x05, 0x15, 0x00, 0x40, + 0x01, 0x05, 0x40, 0x51, 0x00, 0x14, 0x14, 0x40, 0x00, 0xa8, 0x00, 0x00, + 0xa8, 0x28, 0x00, 0x28, 0x28, 0xa8, 0x02, 0x80, 0x0a, 0x0a, 0x00, 0x80, + 0x08, 0x00, 0x00, 0x80, 0x8a, 0x0a, 0x00, 0xa0, 0x80, 0xaa, 0xaa, 0xa8, + 0xaa, 0x2a, 0x0a, 0xa0, 0x01, 0x44, 0x01, 0x00, 0x50, 0x55, 0x00, 0x14, + 0x50, 0x14, 0x01, 0x00, 0x15, 0x05, 0x00, 0x40, 0x15, 0x00, 0x00, 0x00, + 0x15, 0x05, 0x00, 0x50, 0x41, 0x55, 0x55, 0x51, 0x55, 0x15, 0x15, 0x40, + 0x00, 0x80, 0x02, 0x00, 0xa0, 0x28, 0x00, 0x0a, 0x28, 0x0a, 0x02, 0x00, + 0x8a, 0x0a, 0x00, 0xa0, 0x2a, 0x00, 0x00, 0x00, 0x8a, 0x0a, 0x00, 0xa0, + 0x80, 0xaa, 0xaa, 0xa8, 0xaa, 0x2a, 0x0a, 0xa0, 0x01, 0x40, 0x01, 0x00, + 0x50, 0x55, 0x00, 0x14, 0x50, 0x05, 0x00, 0x00, 0x14, 0x05, 0x00, 0x50, + 0x50, 0x00, 0x00, 0x00, 0x15, 0x05, 0x00, 0x50, 0x40, 0x55, 0x55, 0x51, + 0x55, 0x15, 0x05, 0x50, 0x00, 0x80, 0x02, 0x2a, 0xa8, 0x28, 0x00, 0x0a, + 0xa8, 0x0a, 0x80, 0xaa, 0x82, 0x02, 0x00, 0x20, 0xa0, 0x00, 0xa0, 0x82, + 0x8a, 0x0a, 0x00, 0xa0, 0x80, 0x02, 0x00, 0x28, 0x00, 0x00, 0x0a, 0xa0, + 0x00, 0x00, 0x05, 0x14, 0x50, 0x54, 0x00, 0x15, 0x50, 0x05, 0x40, 0x55, + 0x01, 0x05, 0x00, 0x10, 0x40, 0x01, 0x40, 0x01, 0x05, 0x15, 0x50, 0x51, + 0x40, 0x01, 0x00, 0x50, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x0a, 0x2a, + 0xa8, 0xa8, 0x80, 0x0a, 0xa0, 0x02, 0x80, 0x0a, 0x80, 0x02, 0x00, 0x08, + 0x80, 0x02, 0xa0, 0x82, 0x0a, 0x2a, 0xa8, 0xa0, 0x80, 0x02, 0x2a, 0xa8, + 0x80, 0x8a, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x54, 0x55, 0x50, 0x55, 0x05, + 0x50, 0x01, 0x00, 0x00, 0x44, 0x05, 0x00, 0x04, 0x00, 0x05, 0x40, 0x55, + 0x05, 0x54, 0x55, 0x50, 0x00, 0x55, 0x15, 0x50, 0x55, 0x05, 0x05, 0x50, + 0x00, 0x00, 0x00, 0xa8, 0x2a, 0xa0, 0xaa, 0x0a, 0xa0, 0x00, 0x08, 0x00, + 0x8a, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x80, 0xaa, 0x02, 0xaa, 0x2a, 0x28, + 0x80, 0xaa, 0x0a, 0xa0, 0xaa, 0x82, 0x02, 0x28, 0x00, 0x00, 0x00, 0x50, + 0x15, 0x40, 0x55, 0x05, 0x40, 0x01, 0x10, 0x00, 0x55, 0x01, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x55, 0x01, 0x54, 0x15, 0x50, 0x00, 0x55, 0x05, 0x40, + 0x55, 0x01, 0x05, 0x50, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x80, 0x0a, 0x0a, + 0xa0, 0x00, 0x00, 0xa0, 0xaa, 0x02, 0x80, 0x0a, 0x00, 0x00, 0x00, 0x2a, + 0x00, 0xa0, 0x0a, 0x28, 0x00, 0xa8, 0x00, 0x80, 0x2a, 0x80, 0x02, 0x28, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + 0x55, 0x00, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0xa0, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, + 0xaa, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xa8, 0xaa, 0x02, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x55, 0x05, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0x0a, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x55, 0x15, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xaa, 0x8a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x45, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x22, 0xa0, 0x22, 0xa8, 0x0a, 0xa8, 0x00, + 0xa8, 0xa0, 0x28, 0x80, 0xaa, 0x22, 0x28, 0xa0, 0x02, 0x2a, 0x2a, 0xa0, + 0x02, 0x8a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x15, 0x50, 0x15, 0x54, 0x15, 0x54, 0x01, 0x55, 0x41, 0x55, 0x00, + 0x55, 0x11, 0x54, 0x50, 0x05, 0x54, 0x54, 0x54, 0x05, 0x54, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x08, 0x08, + 0x20, 0x08, 0x02, 0x82, 0x82, 0x82, 0x82, 0x00, 0xaa, 0x08, 0x20, 0x20, + 0x08, 0x08, 0x08, 0x0a, 0x0a, 0x28, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x10, 0x04, 0x10, 0x10, 0x00, 0x01, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x54, 0x14, 0x11, 0x00, 0x10, 0x10, 0x04, 0x04, + 0x04, 0x10, 0x00, 0x14, 0x51, 0x10, 0x44, 0x01, 0x50, 0x44, 0x44, 0x14, + 0xa0, 0x00, 0x02, 0x08, 0x08, 0x80, 0x00, 0x82, 0x00, 0x82, 0x80, 0x00, + 0xa8, 0x28, 0x00, 0xa0, 0x0a, 0x20, 0x08, 0x02, 0x08, 0x08, 0x00, 0x00, + 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x05, 0x04, 0x00, + 0x10, 0x00, 0x55, 0x45, 0x55, 0x41, 0x40, 0x00, 0x54, 0x54, 0x00, 0x50, + 0x05, 0x10, 0x04, 0x55, 0x05, 0x04, 0x00, 0x44, 0x10, 0x14, 0x45, 0x04, + 0x10, 0x54, 0x54, 0x04, 0x00, 0x0a, 0x02, 0x00, 0x08, 0x80, 0xaa, 0x82, + 0xaa, 0x82, 0x80, 0x00, 0x2a, 0xaa, 0x00, 0x08, 0x08, 0x20, 0x02, 0xaa, + 0x0a, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, + 0x10, 0x14, 0x04, 0x00, 0x04, 0x00, 0x01, 0x40, 0x00, 0x40, 0x40, 0x00, + 0x15, 0x45, 0x15, 0x04, 0x04, 0x10, 0x01, 0x01, 0x00, 0x04, 0x00, 0x05, + 0x15, 0x10, 0x44, 0x04, 0x14, 0x14, 0x41, 0x04, 0x08, 0x08, 0x0a, 0x08, + 0x08, 0x80, 0x02, 0x82, 0x80, 0x20, 0x20, 0x80, 0x8a, 0x8a, 0x22, 0x02, + 0x02, 0xa0, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x05, 0x54, 0x15, 0x55, 0x01, 0x55, 0x01, + 0x55, 0x51, 0x51, 0x01, 0x45, 0x05, 0x00, 0x54, 0x15, 0x40, 0x00, 0x54, + 0x45, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa8, 0x02, 0xa8, 0x82, 0xaa, 0x00, 0xaa, 0x00, 0x2a, 0xa8, 0xa8, 0x80, + 0x82, 0x22, 0x20, 0xa8, 0x0a, 0x20, 0x00, 0xa8, 0x80, 0xaa, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x55, 0x55, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xa0, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x00, 0x54, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x15, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0xa8, 0xaa, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x2a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x54, 0x00, 0x54, 0x55, 0x01, 0x00, 0x40, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, + 0x00, 0xa8, 0xaa, 0x02, 0x00, 0x80, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x50, 0x55, 0x05, + 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x0a, 0x00, 0xa0, 0xaa, 0x0a, 0x00, 0x00, 0x0a, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, + 0x00, 0x40, 0x55, 0x15, 0x00, 0x00, 0x14, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x80, 0xaa, 0x2a, + 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa8, 0x02, 0x08, 0x00, 0x10, 0x50, 0x50, 0x50, 0x40, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x05, 0x04, 0x01, 0x05, 0x50, 0x40, 0x54, 0x05, 0x04, 0x05, + 0x8a, 0x20, 0x20, 0x88, 0xa0, 0x28, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, + 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x20, 0x00, 0x82, 0x82, 0x08, 0x8a, + 0x82, 0x08, 0x88, 0xa0, 0xa8, 0x0a, 0x22, 0x28, 0x00, 0x41, 0x00, 0x04, + 0x41, 0x44, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x55, 0x55, + 0x00, 0x00, 0x10, 0x00, 0x01, 0x41, 0x10, 0x44, 0x44, 0x10, 0x04, 0x41, + 0x50, 0x15, 0x11, 0x10, 0x80, 0x80, 0x00, 0x02, 0x82, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x80, 0x00, + 0x02, 0x22, 0x20, 0x08, 0x20, 0x20, 0x02, 0x22, 0xa0, 0x2a, 0x22, 0x20, + 0x00, 0x41, 0x10, 0x01, 0x44, 0x00, 0x00, 0x40, 0x41, 0x51, 0x04, 0x14, + 0x15, 0x00, 0x11, 0x44, 0x50, 0x54, 0x40, 0x01, 0x05, 0x10, 0x00, 0x04, + 0x10, 0x40, 0x01, 0x44, 0x10, 0x15, 0x51, 0x00, 0xa8, 0x80, 0x00, 0xaa, + 0x82, 0x00, 0x00, 0x20, 0x22, 0x8a, 0xa2, 0x22, 0x22, 0x80, 0xa0, 0x88, + 0x88, 0x88, 0x88, 0x02, 0x2a, 0x20, 0x00, 0x08, 0xa0, 0x2a, 0xaa, 0x22, + 0x20, 0x8a, 0xa0, 0x02, 0x04, 0x01, 0x01, 0x01, 0x40, 0x00, 0x00, 0x40, + 0x10, 0x10, 0x41, 0x54, 0x11, 0x00, 0x11, 0x40, 0x54, 0x05, 0x04, 0x05, + 0x50, 0x11, 0x00, 0x04, 0x10, 0x00, 0x01, 0x40, 0x10, 0x45, 0x00, 0x15, + 0x82, 0x80, 0x08, 0x02, 0x80, 0x00, 0x00, 0x00, 0x22, 0x88, 0x02, 0x02, + 0x22, 0x00, 0x82, 0x08, 0x02, 0x08, 0x02, 0x0a, 0x80, 0x22, 0x00, 0x08, + 0x20, 0x00, 0x02, 0x20, 0x20, 0xa2, 0x00, 0x28, 0x01, 0x01, 0x05, 0x01, + 0x40, 0x00, 0x00, 0x40, 0x14, 0x51, 0x41, 0x44, 0x11, 0x40, 0x04, 0x11, + 0x04, 0x05, 0x01, 0x14, 0x00, 0x15, 0x00, 0x04, 0x10, 0x00, 0x01, 0x40, + 0x10, 0x51, 0x01, 0x50, 0x82, 0x00, 0x02, 0x02, 0x80, 0x00, 0x00, 0x80, + 0xa2, 0x88, 0x2a, 0x28, 0x22, 0x80, 0x02, 0x28, 0x8a, 0x88, 0x00, 0x28, + 0x00, 0x22, 0x00, 0x08, 0x20, 0x00, 0x02, 0x20, 0xa0, 0xa8, 0x02, 0x20, + 0x01, 0x05, 0x05, 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, + 0x00, 0x00, 0x40, 0x55, 0x15, 0x00, 0x00, 0x00, 0x01, 0x44, 0x00, 0x04, + 0x40, 0x40, 0x04, 0x44, 0x10, 0x51, 0x15, 0x40, 0x82, 0x00, 0x02, 0x08, + 0x82, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, + 0x2a, 0x00, 0x00, 0x00, 0x02, 0x82, 0x08, 0x08, 0x80, 0x20, 0x08, 0x22, + 0xa0, 0xa0, 0x2a, 0x20, 0x14, 0x01, 0x00, 0x50, 0x50, 0x01, 0x00, 0x00, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x15, 0x00, 0x05, 0x50, 0x50, 0x50, 0x40, 0x15, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x28, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x2a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x54, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa0, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x55, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, + 0x00, 0xa0, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x2a, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xaa, 0x15, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, + 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, + 0xa2, 0x00, 0x80, 0x02, 0x0a, 0xa2, 0x82, 0x02, 0x0a, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0xa8, 0xa0, 0x80, 0x82, 0xa0, 0x11, 0x01, 0x00, 0x04, + 0x11, 0x50, 0x41, 0x04, 0x11, 0x10, 0x00, 0x14, 0x44, 0x40, 0x00, 0x41, + 0x11, 0x00, 0x14, 0x00, 0x44, 0x05, 0x05, 0x04, 0x45, 0x00, 0x10, 0x44, + 0x11, 0x11, 0x04, 0x44, 0xa2, 0x02, 0x20, 0x80, 0x20, 0x28, 0x20, 0x08, + 0x02, 0x20, 0x80, 0x22, 0xa8, 0xa8, 0xa0, 0x82, 0x28, 0x00, 0x28, 0x80, + 0x22, 0x08, 0x82, 0x0a, 0x22, 0x80, 0x00, 0x82, 0x20, 0x00, 0x88, 0x8a, + 0x51, 0x05, 0x50, 0x00, 0x10, 0x11, 0x11, 0x10, 0x01, 0x50, 0x40, 0x10, + 0x54, 0x04, 0x11, 0x04, 0x41, 0x00, 0x50, 0x40, 0x10, 0x04, 0x44, 0x10, + 0x44, 0x40, 0x01, 0x01, 0x10, 0x10, 0x44, 0x14, 0xa2, 0x00, 0xa0, 0x00, + 0xa8, 0x02, 0xa0, 0x0a, 0x02, 0xa0, 0xa0, 0x00, 0x0a, 0x82, 0x08, 0x82, + 0x20, 0x00, 0xa0, 0x20, 0x20, 0x08, 0x22, 0x08, 0x02, 0x80, 0x02, 0x02, + 0x20, 0xa8, 0x8a, 0x82, 0x51, 0x01, 0x40, 0x01, 0x55, 0x01, 0x10, 0x00, + 0x01, 0x40, 0x41, 0x00, 0x04, 0x54, 0x50, 0x41, 0x40, 0x00, 0x40, 0x10, + 0x10, 0x04, 0x41, 0x05, 0x01, 0x00, 0x05, 0x01, 0x10, 0x10, 0x40, 0x50, + 0xa2, 0x08, 0x80, 0x82, 0xa0, 0x8a, 0x20, 0x00, 0x02, 0x80, 0x22, 0x00, + 0x02, 0x0a, 0x28, 0x80, 0x20, 0x00, 0x80, 0x20, 0x08, 0x88, 0xa0, 0x00, + 0x02, 0x00, 0x0a, 0x02, 0x20, 0x08, 0x80, 0xa0, 0x51, 0x01, 0x00, 0x44, + 0x50, 0x11, 0x10, 0x00, 0x01, 0x00, 0x11, 0x00, 0x01, 0x01, 0x04, 0x40, + 0x10, 0x00, 0x40, 0x11, 0x10, 0x10, 0x11, 0x00, 0x01, 0x00, 0x10, 0x01, + 0x10, 0x10, 0x40, 0x50, 0xa2, 0x08, 0x00, 0x88, 0x80, 0x08, 0x20, 0x00, + 0x02, 0x02, 0x22, 0x00, 0x02, 0x02, 0x08, 0x20, 0x20, 0x00, 0x80, 0x08, + 0x08, 0x88, 0x20, 0x80, 0x00, 0x00, 0x20, 0x02, 0x20, 0x28, 0x80, 0xa0, + 0x51, 0x11, 0x10, 0x44, 0x40, 0x50, 0x40, 0x10, 0x01, 0x00, 0x11, 0x00, + 0x01, 0x01, 0x04, 0x40, 0x10, 0x00, 0x01, 0x11, 0x04, 0x50, 0x10, 0x00, + 0x01, 0x40, 0x10, 0x04, 0x11, 0x50, 0x00, 0x01, 0xa2, 0x28, 0x20, 0x82, + 0x0a, 0x20, 0xa0, 0x0a, 0x02, 0x02, 0x22, 0x88, 0x00, 0x82, 0x08, 0x22, + 0x08, 0x80, 0x80, 0x28, 0x08, 0x28, 0x20, 0x88, 0x00, 0x80, 0x08, 0xaa, + 0x20, 0xa0, 0x82, 0xaa, 0x41, 0x50, 0x50, 0x01, 0x55, 0x00, 0x00, 0x05, + 0x05, 0x05, 0x51, 0x04, 0x01, 0x45, 0x14, 0x11, 0x50, 0x00, 0x41, 0x50, + 0x04, 0x10, 0x50, 0x44, 0x00, 0x40, 0x05, 0x50, 0x50, 0x40, 0x01, 0x14, + 0xaa, 0xaa, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xa0, 0x82, + 0x00, 0x2a, 0xa8, 0x20, 0x28, 0x80, 0x2a, 0x20, 0x08, 0x08, 0xa0, 0x82, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0xaa, 0x02, 0x80, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x55, 0x01, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xaa, 0x02, 0xa0, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0x05, 0x40, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa0, 0xaa, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x15, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0x2a, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x55, 0x55, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x2a, 0x2a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xaa, 0x8a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x45, 0x45, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x88, 0xa2, 0x22, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x88, 0x00, 0x00, 0x80, 0xaa, 0x2a, 0x0a, 0x00, 0x0a, 0x08, + 0x02, 0x22, 0xa0, 0x80, 0x08, 0x00, 0xa0, 0x00, 0x20, 0xa0, 0xa0, 0xa0, + 0x41, 0x01, 0x51, 0x45, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, + 0x00, 0x00, 0x55, 0x55, 0x14, 0x00, 0x11, 0x14, 0x05, 0x45, 0x10, 0x41, + 0x11, 0x00, 0x40, 0x01, 0x14, 0x41, 0x40, 0x10, 0x82, 0x28, 0xa2, 0xaa, + 0x80, 0xa2, 0xa2, 0xa0, 0xa8, 0x00, 0x28, 0x28, 0x08, 0xa2, 0x02, 0xaa, + 0xa8, 0x80, 0x20, 0x88, 0x88, 0x0a, 0x08, 0x82, 0x20, 0x00, 0x80, 0x0a, + 0x00, 0x82, 0x00, 0x08, 0x04, 0x51, 0x51, 0x55, 0x45, 0x44, 0x11, 0x11, + 0x11, 0x01, 0x50, 0x44, 0x04, 0x11, 0x05, 0x55, 0x41, 0x41, 0x40, 0x10, + 0x40, 0x55, 0x04, 0x44, 0x40, 0x00, 0x00, 0x14, 0x00, 0x01, 0x01, 0x04, + 0x88, 0xa8, 0xa8, 0x2a, 0x2a, 0x20, 0x08, 0x0a, 0x0a, 0x02, 0xa0, 0x80, + 0x88, 0x08, 0xa2, 0xaa, 0x02, 0x22, 0x00, 0x08, 0xa0, 0x8a, 0x02, 0x88, + 0x20, 0x00, 0x00, 0x20, 0x00, 0x82, 0x20, 0x02, 0x05, 0x55, 0x54, 0x55, + 0x44, 0x40, 0x50, 0x51, 0x11, 0x01, 0x04, 0x51, 0x10, 0x51, 0x41, 0x55, + 0x05, 0x44, 0x00, 0x10, 0x00, 0x50, 0x54, 0x45, 0x40, 0x00, 0x00, 0x40, + 0x50, 0x01, 0x01, 0x54, 0x80, 0x2a, 0xaa, 0x0a, 0x28, 0x28, 0x08, 0x08, + 0x08, 0x02, 0x88, 0x88, 0x80, 0x08, 0xa8, 0xaa, 0x0a, 0x28, 0x00, 0x08, + 0xa0, 0x02, 0x02, 0x80, 0x20, 0x00, 0x00, 0x80, 0x08, 0x02, 0x02, 0x02, + 0x00, 0x15, 0x55, 0x15, 0x44, 0x44, 0x10, 0x11, 0x11, 0x01, 0x04, 0x45, + 0x50, 0x10, 0x51, 0x55, 0x15, 0x44, 0x00, 0x10, 0x00, 0x01, 0x04, 0x40, + 0x40, 0x00, 0x00, 0x40, 0x04, 0x01, 0x11, 0x04, 0x80, 0x0a, 0xaa, 0x2a, + 0x82, 0x22, 0xa0, 0xa0, 0x08, 0x02, 0xa8, 0xa8, 0x20, 0xa0, 0xa8, 0xaa, + 0x0a, 0x28, 0x00, 0x08, 0x80, 0x00, 0x02, 0x80, 0x20, 0x00, 0x00, 0x80, + 0x02, 0x02, 0x0a, 0x02, 0x00, 0x04, 0x54, 0x55, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x15, 0x44, 0x00, 0x10, + 0x10, 0x00, 0x04, 0x40, 0x40, 0x00, 0x00, 0x40, 0x04, 0x01, 0x04, 0x04, + 0x08, 0x02, 0xa8, 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xaa, 0x28, 0x82, 0x00, 0x08, 0xa8, 0x80, 0x08, 0x88, + 0x20, 0x00, 0x20, 0x20, 0x02, 0x0a, 0x0a, 0x08, 0x44, 0x00, 0x50, 0x55, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + 0x51, 0x01, 0x11, 0x10, 0x54, 0x41, 0x10, 0x44, 0x40, 0x00, 0x40, 0x10, + 0x04, 0x01, 0x04, 0x10, 0x00, 0x00, 0xa0, 0xaa, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x00, 0x08, 0x00, 0x00, 0x00, 0xaa, 0x08, 0x00, 0x0a, 0x2a, + 0x2a, 0x0a, 0xa0, 0xa0, 0xa0, 0x00, 0x20, 0x0a, 0x28, 0x02, 0x00, 0xa0, + 0x50, 0x01, 0x50, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/nx-X11/programs/Xserver/hw/nxagent/x2go.xpm b/nx-X11/programs/Xserver/hw/nxagent/x2go.xpm new file mode 100644 index 000000000..46a74eab9 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/nxagent/x2go.xpm @@ -0,0 +1,163 @@ +/**************************************************************************/ +/* */ +/* Copyright 2008 Heinz-M. Graesing <heinz-m.graesing@obviously-nice.de> */ +/* */ +/* NXAGENT, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +/* XPM */ +static char *x2goagentIconData[]={ +"128 128 17 1", +". c None", +"m c #323232", +"l c #323232", +"f c #323232", +"e c #323232", +"o c #323232", +"# c #323232", +"h c #323232", +"i c #323232", +"n c #323232", +"d c #323232", +"a c #323232", +"g c #323232", +"j c #323232", +"b c #323232", +"k c #323232", +"c c #323232", +".....#abccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbde.....", +"...fbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccgf...", +"..#ccccaheeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeijccckf..", +".ecccgl..................................................................................................................ejcckf.", +".bccd.....................................................................................................................mdccg.", +"#cca.......................................................................................................................mjcce", +"gckm........................................................................................................................eccd", +"ccn..........................................................................................................................jcb", +"cce..........................................................................................................................icc", +"ccm..........................................................................................................................ecc", +"cc...........................................................................................................................ecc", +"cc...........................................................................................................................ecc", +"cc...........................................................................................................................ecc", +"cc...........................................................................................................................ecc", +"cc............................................meeee..........................................................................ecc", +"cc.........eeeeeeeeoiiiiiiiinggggggggjccccccccccccc....#ggggggggggggggggggggggggggggf.............ggggggggggggggggggggggf....ecc", +"cc....meeeeoiiiiiiiinggggggggjccccccccccccccccccccc....icccccccccccccccccccccccccccce.............cccccccccccccccccccccce....ecc", +"cc....................................meeeeeeeeoiii....icccccccccccccccccccccccccccce.............cccccccccccccccccccccce....ecc", +"cc.......................................................menbccccccccccccccccccbhe..................logccccccccccccghe.......ecc", +"cc...........................................................iccccccccccccccccdm.......................#cccccccccke..........ecc", +"cc..............................................lee...........#cccccccccccccckm.........................jccccccckm...........ecc", +"cc........feeeeeeeeoiiiiiiiiiaggggggggjcccccccccccc............icccccccccccccd..........................icccccccf............ecc", +"cc....meeeeeoiiiiiiiinggggggggjcccccccccccccccccccciiiiii#m.....jcccccccccccci..........................icccccci.............ecc", +"cc......................................eeeeeeeeeiiiiiiiiigl....eccccccccccccd..........................dcccccj..............ecc", +"cc...............................................................dcccccccccccj..........................bccccce..............ecc", +"cc...............................................................lccccccccccccl........................lccccca...............ecc", +"cc.............................................meeeeeeee#iiiie....dccccccccccch........................icccccl...............ecc", +"cc.........meeeeeeeeoiiiiiiiinggggggggjccccccccccccccccccccccb....ecccccccccccb........................bccccn................ecc", +"cc....meeeeiiiiiiiiiaggggggggbcccccccccccccccccccccccccccccccc#....gccccccccccco......................#cccckm................ecc", +"cc....................................meeeeeeeeeiiiiiiiiiaggggd....#cccccccccccg......................bcccci.................ecc", +"cc..................................................................bcccccccccccf....................#cccckm.................ecc", +"cc..................................................................hcccccccccccd...................mkcccci..................ecc", +"cc............................................meeeeeeeeoiiiiiiiil...mkcccccccccccl..................icccckm..................ecc", +"cc.........eeeeeeeeoiiiiiiiinggggggggjccccccccccccccccccccccccccn....dccccccccccci.................mkcccci...................ecc", +"cc....meeeeeiiiiiiiiiaggggggggbccccccccccccccccccccccccccccccccckm...lccccccccccck.................icccckm...................ecc", +"cc.....................................leeeeeeeeoiiiiiiiiigggggggo....accccccccccc#...............mkcccch....................ecc", +"cc....................................................................ecccccccccccb...............iccccb.....................ecc", +"cc.....................................................................jccccccccccce.............mkcccc#.....................ecc", +"cc.............................................meeeeeeeeehiiiiiiii#....#ccccccccccca.............nccccb......................ecc", +"cc........feeeeeeee#iiiiiiiiigggggggggkccccccccccccccccccccccccccccl....kcccccccccccl...........lccccc#......................ecc", +"cc....meeeeeoiiiiiiiiigggggggggkcccccccccccccccccccccccccccccccccccd....icccccccccccd...........dccccb.......................ecc", +"cc......................................leeeeeeeeoiiiiiiiingggggggga....mccccccccccckm.........lccccc#.......................ecc", +"cc.......................................................................dccccccccccch.........dccccb........................ecc", +"cc.......................................................................lcccccccccccb........lccccc#........................ecc", +"cc.............................................meeeeeeeeoiiiiiiiingggo....gccccccccccc#.......dccccg.........................ecc", +"cc.........meeeeeeeeoiiiiiiiinggggggggjccccccccccccccccccccccccccccccg....occcccccccccg......lccccce.........................ecc", +"cc....meeeeiiiiiiiiiaggggggggbcccccccccccccccccccccccccccccccccccccccce....bccccccccccce.....gccccg..........................ecc", +"cc....................................meeeeeeeeeiiiiiiiiigggggggggkcccd....#cccccccccccd....eccccce..........................ecc", +"cc.........................................................................mkcccccccccccl...gccccg...........................ecc", +"cc..........................................................................nccccccccccci..eccccce...........................ecc", +"cc............................................meeeeeeeeoiiiiiiiingggggggm...lccccccccccckm.gccccg............................ecc", +"cc.........eeeeeeeeoiiiiiiiinggggggggjcccccccccccccccccccccccccccccccccc#....dccccccccccc#eccccce............................ecc", +"cc....meeeeeiiiiiiiiiaggggggggkcccccccccccccccccccccccccccccccccccccccccb....ecccccccccccbgccccg.............................ecc", +"cc.....................................leeeeeeeeoiiiiiiiiigggggggggkccccco....gccccccccccccccccl.............................ecc", +"cc............................................................................#cccccccccccccccd..............................ecc", +"cc.............................................................................bccccccccccccccl..............................ecc", +"cc.............................................leeeeeeeeeiiiiiiiiiagggggggi....icccccccccccccd...............................ecc", +"cc........feeeeeeee#iiiiiiiingggggggggkccccccccccccccccccccccccccccccccccckm...mkccccccccccccl...............................ecc", +"cc....meeeeeoiiiiiiiiigggggggggkccccccccccccccccccccccccccccccccccccccccccci....dccccccccccca................................ecc", +"cc......................................leeeeeeeeoiiiiiiiiigggggggggccccccck....lccccccccccckm...............................ecc", +"cc...............................................................................accccccccccc#...............................ecc", +"cc...............................................................................ecccccccccccb...............................ecc", +"cc............................................leeeeeeeeeiiiiiiiiiaggggggggbcce....bccccccccccce..............................ecc", +"cc.......feeeeeeee#iiiiiiiiigggggggggkcccccccccccccccccccccccccccccccccccccccd....#cccccccccccg..............................ecc", +"cc....meeeeeeoiiiiiiiingggggggggccccccccccccccccccccccccccccccccccccccccccccccl....kcccccccccccl.............................ecc", +"cc.......................................feeeeeeeehiiiiiiiidggggggggbccccccccci....ncccccccccccd.............................ecc", +"cc...........................................................................mm....bccccccccccccm............................ecc", +"cc................................................................................#ccccccccccccci............................ecc", +"cc..........................................leeeeeeee#iiiiiiiidggggggggbcccccl....bccccccccccccck............................ecc", +"cc......feeeeeeeehiiiiiiiiaggggggggkccccccccccccccccccccccccccccccccccccccccd....#ccccccccccccccc#...........................ecc", +"cc....meeeeeee#iiiiiiiidggggggggjcccccccccccccccccccccccccccccccccccccccccccl....bcccccccccccccccb...........................ecc", +"cc.......................................meeeeeeeeeiiiiiiiiigggggggggkcccccd....#cccccbccccccccccce..........................ecc", +"cc..............................................................................bccccdhcccccccccccg..........................ecc", +"cc.............................................................................#ccccclmkcccccccccccl.........................ecc", +"cc..........................................meeeeeeeeeiiiiiiiiiaggggggggbkm....bccccd..ncccccccccccd.........................ecc", +"cc.....leeeeeeeeoiiiiiiiiigggggggggkccccccccccccccccccccccccccccccccccccci....hcccckl..lccccccccccccm........................ecc", +"cc....meeeeeeeehiiiiiiiidggggggggbcccccccccccccccccccccccccccccccccccccckm...mkcccci....dccccccccccci........................ecc", +"cc........................................leeeeeeee#iiiiiiiinggggggggjcci....icccckm....eccccccccccck........................ecc", +"cc..........................................................................mkcccci......gccccccccccc#.......................ecc", +"cc..........................................................................icccckm......#cccccccccccb.......................ecc", +"cc.........................................leeeeeeeeoiiiiiiiiigggggggga....mkcccci........bccccccccccce......................ecc", +"cc....meeeeeeeeoiiiiiiiiigggggggggkccccccccccccccccccccccccccccccccccci....icccckm........hcccccccccccg......................ecc", +"cc.....feeeeeeeehiiiiiiiiaggggggggkcccccccccccccccccccccccccccccccccckm...mkcccci.........mkcccccccccccl.....................ecc", +"cc.........................................feeeeeeeehiiiiiiiiagggggggh....icccckm..........icccccccccccd.....................ecc", +"cc.......................................................................mkcccci...........lccccccccccccm....................ecc", +"cc.......................................................................icccckm............dccccccccccci....................ecc", +"cc...........................................eeeeeeeeehiiiiiiiidggga....mkcccci.............fccccccccccck....................ecc", +"cc......feeeeeeee#iiiiiiiingggggggggccccccccccccccccccccccccccccccci....iccccb...............gccccccccccc#...................ecc", +"cc....meeeeeeeoiiiiiiiiigggggggggbcccccccccccccccccccccccccccccccckm...mkcccc#...............occcccccccccb...................ecc", +"cc........................................meeeeeeeeeiiiiiiiiidgggg#....iccccb.................bccccccccccce..................ecc", +"cc....................................................................mkcccc#.................#cccccccccccg..................ecc", +"cc....................................................................iccccb..................mkcccccccccccl.................ecc", +"cc..........................................eeeeeeeeeiiiiiiiiiaga....mkcccc#...................icccccccccccd.................ecc", +"cc.....leeeeeeee#iiiiiiiinggggggggjccccccccccccccccccccccccccccci....iccccb....................lccccccccccccm................ecc", +"cc....meeeeeeee#iiiiiiiiigggggggggkcccccccccccccccccccccccccccckm...mkcccc#.....................dccccccccccci................ecc", +"cc.........................................leeeeeeeeoiiiiiiiiiah....iccccb......................lccccccccccck................ecc", +"cc.................................................................mkcccc#.......................gccccccccccc#...............ecc", +"cc.................................................................dccccj........................ecccccccccccj...............ecc", +"cc..........................................leeeeeeeeeiiiiiiih....lccccce.........................bccccccccccce..............ecc", +"cc....meeeeeeeeeiiiiiiiiidgggggggggcccccccccccccccccccccccccci....dccccg..........................#ccccccccccca..............ecc", +"cc.....feeeeeeeeiiiiiiiinggggggggbcccccccccccccccccccccccccckm...lccccce...........................kcccccccccccl.............ecc", +"cc........................................leeeeeeeehiiiiiiiih....dccccg............................ncccccccccccd.............ecc", +"cc..............................................................lccccce............................fccccccccccccf............ecc", +"cc..............................................................dccccb..............................jcccccccccccg............ecc", +"cc.........................................meeeeeeeeoiiiiil....lcccccn..............................icccccccccccce...........ecc", +"cc......feeeeeeeehiiiiiiiigggggggggccccccccccccccccjgggggo.....gccccc#..............................eccccccccccccbm..........ecc", +"cc....meeeeeeeoiiiiiiiiidgggggggggccccccccccccccccc...........hcccccco...............................cccccccccccccn..........ecc", +"cc.........................................leeeeeee..........ecccccccn..............................lcccccccccccccc#.........ecc", +"cc..........................................................#kccccccckf.............................nccccccccccccccc#........ecc", +"cc........................................................ldcccccccccck#m.........................lncccccccccccccccccdl......ecc", +"cc.........................................feeeeeee....ogjcccccccccccccccggi..................oggbcccccccccccccccccccccja....ecc", +"cc.....leeeeeeee#iiiiiiiidggggggggbcccccccccccccccc....icccccccccccccccccccg..................icccccccccccccccccccccccccc....ecc", +"cc....meeeeeeeehiiiiiiiiaggggggggkccccccccccccccccc....icccccccccccccccccccg..................icccccccccccccccccccccccccc....ecc", +"cc........................................feeeeeeee..........................................................................ecc", +"cc...........................................................................................................................ecc", +"cc...........................................................................................................................ecc", +"cc...........................................................................................................................ecc", +"cc...........................................................................................................................ecc", +"cc...........................................................................................................................ecc", +"cce..........................................................................................................................hcc", +"ccn..........................................................................................................................acb", +"jcb.........................................................................................................................lcca", +"hcci........................................................................................................................acc#", +"mkcc#......................................................................................................................dccb.", +".occci...................................................................................................................macccf.", +"..#cccbne.............................................................................................................menkccc#..", +"...okccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbe...", +"....mhjccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccg#....."}; |