aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/Xserver/hw/nxagent/Rootless.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/programs/Xserver/hw/nxagent/Rootless.c')
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Rootless.c1248
1 files changed, 1248 insertions, 0 deletions
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..74d2d1fe5
--- /dev/null
+++ b/nx-X11/programs/Xserver/hw/nxagent/Rootless.c
@@ -0,0 +1,1248 @@
+/**************************************************************************/
+/* */
+/* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/. */
+/* */
+/* NXAGENT, NX protocol compression and NX extensions to this software */
+/* are copyright of NoMachine. Redistribution and use of the present */
+/* software is allowed according to terms specified in the file LICENSE */
+/* which comes in the source distribution. */
+/* */
+/* Check http://www.nomachine.com/licensing.html for applicability. */
+/* */
+/* NX and NoMachine are trademarks of Medialogic S.p.A. */
+/* */
+/* All rights reserved. */
+/* */
+/**************************************************************************/
+
+#include "X.h"
+
+#include "../../include/window.h"
+#include "windowstr.h"
+#include "colormapst.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 "NXlib.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 = WindowTable[0] -> 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 != WindowTable[0])
+ {
+ 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 = xalloc(sizeof(WindowPtr) * nchildren);
+ ntoplevel = 0;
+
+ for(i = 0; i < nchildren; i++)
+ {
+ pWin = nxagentWindowPtr(children[i]);
+
+ if (!pWin)
+ {
+ pWin = nxagentRootlessTopLevelWindow(children[i]);
+ }
+
+ if (pWin && pWin != WindowTable[0])
+ {
+ toplevel[ntoplevel++] = pWin;
+ }
+ }
+
+ if (!ntoplevel)
+ {
+ return;
+ }
+
+ #ifdef DEBUG
+
+ fprintf(stderr, "nxagentRootlessRestack: External top level windows before restack:");
+
+ for (i = 0; i < ntoplevel; i++)
+ {
+ fprintf(stderr, "[%p]\n", toplevel[i]);
+ }
+
+ fprintf(stderr, "nxagentRootlessRestack: Internal top level windows before restack:");
+
+ for (pWin = WindowTable[0] -> firstChild; pWin != NULL; pWin = pWin -> nextSib)
+ {
+ fprintf(stderr, "[%p]\n", pWin);
+ }
+
+ #endif
+
+ pWin = WindowTable[0] -> 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, "[%p]\n", toplevel[i]);
+ }
+
+ fprintf(stderr, "nxagentRootlessRestack: Internal top level windows after restack:");
+
+ for (pWin = WindowTable[0] -> firstChild; pWin != NULL; pWin = pWin -> nextSib)
+ {
+ fprintf(stderr, "[%p]\n", pWin);
+ }
+
+ #endif
+
+ xfree(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;
+ pointer value;
+{
+ 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)
+ {
+ 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, SecurityDestroyAccess);
+
+ 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,
+ SecurityDestroyAccess);
+
+ 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, SecurityDestroyAccess);
+
+ 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,
+ SecurityDestroyAccess);
+
+ 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;
+ char *atomName = NULL;
+ int i;
+ int j = 0;
+
+ 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;
+
+ freeMem = True;
+ export = True;
+ output = (char*) wind;
+
+ for (i = 0; i < nUnits; i++)
+ {
+ pWindow = (WindowPtr)SecurityLookupWindow(input[i], pClient,
+ SecurityDestroyAccess);
+ 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", 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)
+ {
+ xfree(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;
+ 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 bailing out.\n");
+ #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;
+
+ 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)
+ {
+ xfree(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;
+ }
+
+ xfree(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;
+}
+