/**************************************************************************/ /* */ /* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ /* Copyright (c) 2008-2014 Oleksandr Shneyder */ /* Copyright (c) 2011-2016 Mike Gabriel */ /* Copyright (c) 2014-2016 Mihai Moldovan */ /* Copyright (c) 2014-2016 Ulrich Sibiller */ /* 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(void) { fprintf(stderr, "nxagentPrintRootlessTopLevelWindowMap: Map size is [%d] num of entry [%d].\n", topLevelParentMap.size, topLevelParentMap.next); for (int 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) { for (int 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) { for (int i = 0; i < topLevelParentMap.next; i++) { if (w == topLevelParentMap.elt[i].xid) { return topLevelParentMap.elt[i].pWin; } } return NULL; } void nxagentRootlessDelTopLevelWindow(WindowPtr pWin) { for (int 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(void) { Window root_return; Window parent_return; Window *children_return = NULL; unsigned int nChildrenReturn; 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) { WindowPtr 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; } } } SAFE_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) { SAFE_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 SAFE_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 [0x%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; if (buffer) { freeMem = True; export = True; output = (char*) buffer; for (int 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 [0x%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 [0x%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 [0x%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 [0x%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 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 (int 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; 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 (int 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) { char * data = (char *) output; XDeleteProperty(nxagentDisplay, nxagentWindow(pWin), propertyX); while (nUnits > 0) { int n; 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 [0x%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) { SAFE_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 [0x%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 [0x%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, "nxagentImportProperty: WARNING! Failed to look up remote icon " "window [0x%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 [0x%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 [0x%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; 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 (int 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; 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 (int 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 [0x%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 [0x%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 [0x%lx] property [%ld] type [%s] ntems [%ld] format [%d]\n", window, property, validateString(typeS), nitems, format); #endif } if (freeMem) { SAFE_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(void) { struct nxagentPropertyRec *tmp = nxagentPropertyList.first; #ifdef TEST fprintf(stderr, "nxagentRemovePropertyFromList: Property [%ld] on Window [0x%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; } SAFE_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 [0x%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(void) { 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 [0x%lx] property [%ld].\n", X -> window, X -> atom); if (first) { fprintf(stderr, "nxagentNotifyMatchChangeProperty: First element on list is window [0x%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; }