2025-08-08 20:00:36 +02:00

1282 lines
34 KiB
C

/**************************************************************************/
/* */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
/* Copyright (c) 2014-2022 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 "Atoms.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);
#if 0
/*
* This is currently unused.
*/
#ifdef TEST
static void nxagentPrintRootlessTopLevelWindowMap(void);
void nxagentPrintRootlessTopLevelWindowMap(void)
{
fprintf(stderr, "%s: Map size is [%d] num of entry [%d].\n", __func__,
topLevelParentMap.size, topLevelParentMap.next);
for (int i = 0; i < topLevelParentMap.next; i++)
{
fprintf(stderr, "%s:: [%d] pWin at [%p] XID at [%ld].\n", __func__,
i, (void *) topLevelParentMap.elt[i].pWin, (long int) topLevelParentMap.elt[i].xid);
}
}
#endif
#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, "%s: WARNING! Trying to add duplicated entry window at [%p] xid [%d].\n",
__func__, (void *) pWin, w);
#endif
topLevelParentMap.elt[i].xid = w;
return;
}
}
if (topLevelParentMap.next == topLevelParentMap.size)
{
size_t size = (topLevelParentMap.size += TOP_LEVEL_TABLE_UNIT);
TopLevelParentRec *ptr = realloc(topLevelParentMap.elt, size * sizeof(TopLevelParentRec));
if (ptr == NULL)
{
#ifdef WARNING
fprintf(stderr, "%s: Warning failed to allocate memory.\n", __func__);
#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;
}
}
}
void nxagentConfigureRootlessWindow(WindowPtr pWin, int x, int y, int w, int h, int bw,
WindowPtr pSib, int stack_mode, Mask mask)
{
XWindowChanges changes = {
.x = x,
.y = y,
.width = w,
.height = h,
.border_width = bw,
.stack_mode = stack_mode
};
if (pSib)
{
changes.sibling = nxagentWindow(pSib);
}
XConfigureWindow(nxagentDisplay, nxagentWindow(pWin), mask, &changes);
}
void nxagentCirculateRootlessWindows(int direction)
{
XCirculateSubwindows(nxagentDisplay, DefaultRootWindow(nxagentDisplay), direction);
}
#ifdef DEBUG
Bool nxagentRootlessTreesMatch(void)
{
XlibWindow root_return;
XlibWindow parent_return;
XlibWindow *children_return = NULL;
unsigned int nChildrenReturn;
WindowPtr pTestWin = screenInfo.screens[0]->root -> firstChild;
Bool treesMatch = True;
Status result = XQueryTree(nxagentDisplay, DefaultRootWindow(nxagentDisplay),
&root_return, &parent_return, &children_return, &nChildrenReturn);
if (!result)
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Failed QueryTree request.\n", __func__);
#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 = malloc(sizeof(WindowPtr) * nchildren);
if (!toplevel)
{
/* FIXME: Is this too much and we should simply return here? */
FatalError("nxagentRootlessRestack: malloc() failed.");
}
unsigned int ntoplevel = 0;
for(int i = 0; i < nchildren; i++)
{
WindowPtr 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, "%s: External top level windows before restack:\n", __func__);
for (int i = 0; i < ntoplevel; i++)
{
fprintf(stderr, "%s: [%p]\n", __func__, (void *)toplevel[i]);
}
fprintf(stderr, "%s: Internal top level windows before restack:\n", __func__);
for (WindowPtr pWin = screenInfo.screens[0]->root -> firstChild; pWin != NULL; pWin = pWin -> nextSib)
{
fprintf(stderr, "%s: [%p]\n", __func__, (void *)pWin);
}
#endif
WindowPtr pWin = screenInfo.screens[0]->root -> firstChild;
XID values[2] = {0, (XID) Above};
for (int i = ntoplevel; i-- && pWin; pWin = toplevel[i] -> nextSib)
{
if (toplevel[i] != pWin)
{
Mask mask = CWSibling | CWStackMode;
values[0] = pWin -> drawable.id;
ClientPtr pClient = wClient(toplevel[i]);
nxagentScreenTrap = True;
ConfigureWindow(toplevel[i], mask, values, pClient);
nxagentScreenTrap = False;
#ifdef TEST
fprintf(stderr, "%s: Restacked window [%p].\n", __func__, (void*) toplevel[i]);
#endif
}
}
#ifdef DEBUG
fprintf(stderr, "%s: External top level windows after restack:\n", __func__);
for (int i = 0; i < ntoplevel; i++)
{
fprintf(stderr, "%s: [%p]\n", __func__, (void *)toplevel[i]);
}
fprintf(stderr, "%s: Internal top level windows after restack:\n", __func__);
for (pWin = screenInfo.screens[0]->root -> firstChild; pWin != NULL; pWin = pWin -> nextSib)
{
fprintf(stderr, "%s: [%p]\n", __func__, (void *)pWin);
}
#endif
SAFE_free(toplevel);
return;
}
/*
* Determine if window is a top-level window.
*/
Window nxagentRootlessWindowParent(WindowPtr pWin)
{
#ifdef TEST
fprintf(stderr, "%s: Called for window at [%p][%d] with parent [%p][%d].\n", __func__,
(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(WindowPtr pWin)
{
int total = 0;
for (PropertyPtr pProp = wUserProps(pWin); pProp; pProp = pProp->next)
{
total += nxagentExportProperty(pWin,
pProp->propertyName,
pProp->type,
pProp->format,
PropModeReplace,
pProp->size,
pProp->data);
}
return total;
}
/*
* Export a property from an agent window to the corresponding window
* on the real X server This is e.g. called if a client changes a
* property.
*/
int nxagentExportProperty(WindowPtr pWin,
Atom property,
Atom type,
int format,
int mode,
unsigned long nUnits,
void *value)
{
char *output = NULL;
Bool export = False;
Bool freeMem = False;
if (NXDisplayError(nxagentDisplay) == 1)
{
return 0;
}
const char *propertyS = NameForAtom(property);
const char *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, "%s: WARNING! Ignored ChangeProperty on %swindow [0x%x] property [%s] "
"type [%s] nUnits [%ld] format [%d]\n", __func__,
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));
if (buffer == NULL)
{
FatalError("%s: malloc() failed.", __func__);
}
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);
nxagentWMHints wmHints = *(nxagentWMHints*)value;
wmHints.flags |= InputHint;
wmHints.input = True;
/*
* Initialize the structure used in XChangeProperty().
*/
nxagentPropWMHints propHints = {
.flags = wmHints.flags,
/*.input = (wmHints.input == True ? 1 : 0), is always True*/
.input = 1,
.initialState = wmHints.initial_state,
.iconPixmap = wmHints.icon_pixmap,
.iconWindow = wmHints.icon_window,
.iconX = wmHints.icon_x,
.iconY = wmHints.icon_y,
.iconMask = wmHints.icon_mask,
.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, "%s: WARNING! Failed to look up icon pixmap [0x%x] from hint "
"exporting property [%s] type [%s] on window [%p].\n", __func__,
(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, "%s: WARNING! Failed to look up icon window [0x%x] from hint "
"exporting property [%s] type [%s] on window [%p].\n", __func__,
(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, "%s: WARNING! Failed to look up icon mask [0x%x] from hint "
"exporting property [%s] type [%s] on window [%p].\n", __func__,
(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, "%s: WARNING! Failed to look up window group [0x%x] from hint "
"exporting property [%s] type [%s] on window [%p].\n", __func__,
(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, "%s: WARNING! malloc() failed for '[%s]'- bailing out.\n", __func__, 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, "%s: WARNING! Failed to convert local atom [%ld] [%s].\n", __func__,
(long int) input[i], validateString(atomName));
#endif
}
j++;
}
#ifdef TEST
else
{
fprintf(stderr, "%s: WARNING! "
"Not exporting the _NET_WM_PING property.\n", __func__);
}
#endif
}
nUnits = j;
}
else if (strcmp(typeS, "WINDOW") == 0)
{
Window *input = value;
XlibWindow *wind = malloc(nUnits * sizeof(*wind));
ClientPtr pClient = wClient(pWin);
if (!wind)
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! malloc() failed for '[%s]' - bailing out.\n", __func__, typeS);
#endif
return False;
}
freeMem = True;
export = True;
output = (char*) wind;
for (int i = 0; i < nUnits; i++)
{
WindowPtr pWindow = (WindowPtr)SecurityLookupWindow(input[i], pClient,
DixDestroyAccess);
if ((input[i] != None) && pWindow)
{
wind[i] = nxagentWindow(pWindow);
}
else
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Failed to look up window [%ld] "
"exporting property [%s] type [%s] on window [%p].\n", __func__,
(long int) input[i], propertyS, typeS, (void *) pWin);
#endif
/*
* It seems that clients specify strange windows, perhaps are
* not real windows so we can try to let them pass anyway.
*
* wind[i] = None;
*/
}
}
}
if (export)
{
XlibAtom propertyX = nxagentLocalToRemoteAtom(property);
XlibAtom typeX = nxagentLocalToRemoteAtom(type);
if (propertyX == None || typeX == None)
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Failed to convert local atom.\n", __func__);
#endif
export = 0;
}
else
{
#ifdef TEST
fprintf(stderr, "%s: Property [%lu] format [%i] units [%lu].\n", __func__,
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, "%s: WARNING! Property [%lu] too long.\n", __func__,
(long unsigned int)propertyX);
#endif
goto nxagentExportPropertyError;
}
nxagentAddPropertyToList(propertyX, pWin);
}
}
else
{
#ifdef TEST
fprintf(stderr, "%s: WARNING! Ignored ChangeProperty on %swindow [0x%x] property [%s] "
"type [%s] nUnits [%ld] format [%d]\n", __func__,
nxagentWindowTopLevel(pWin) ? "toplevel " : "",
nxagentWindow(pWin), validateString(propertyS), validateString(typeS),
nUnits, format);
#endif
}
nxagentExportPropertyError:
if (freeMem)
{
SAFE_free(output);
}
return export;
}
/*
* Import a property from the proxy window on the real X server into
* the agent's corresponding window. This is e.g. called on reception
* of a property change event on the real X server.
*/
void nxagentImportProperty(Window window,
XlibAtom property,
XlibAtom type,
int format,
unsigned long nitems,
unsigned long bytes_after,
unsigned char *buffer)
{
Bool import = False;
Bool freeMem = False;
typedef struct {
CARD32 state;
Window icon;
} WMState;
WMState wmState;
char *output = NULL;
WindowPtr pWin = nxagentWindowPtr(window);
if (pWin == NULL)
{
#ifdef TEST
fprintf(stderr, "%s: Failed to look up remote window [0x%x] property [%ld] exiting.\n",
__func__, window, property);
#endif
return;
}
Atom propertyL = nxagentRemoteToLocalAtom(property);
if (!ValidAtom(propertyL))
{
#ifdef TEST
fprintf(stderr, "%s: Failed to convert remote property atom [%ld].\n", __func__, property);
#endif
return;
}
#ifdef TEST
fprintf(stderr, "%s: Window [0x%x] property: remote [%ld][%s] local [%d]\n", __func__,
window, property, validateString(NameForAtom(propertyL)), propertyL);
#endif
/*
* We settle a property size limit of 256K beyond which we simply
* ignore them.
* FIXME: where's this checked/set/enforced/whatever?
*/
Atom typeL = nxagentRemoteToLocalAtom(type);
const char *typeS = NameForAtom(typeL);
#ifdef TEST
fprintf(stderr, "%s: type: remote [%ld] local [%d][%s].\n", __func__, type, typeL, validateString(typeS));
#endif
if (buffer == NULL && (nitems > 0))
{
#ifdef WARNING
fprintf(stderr, "%s: Failed to retrieve remote property [%ld] [%s] on window [%ld]\n", __func__,
(long int) property, validateString(NameForAtom(propertyL)), (long int) window);
#endif
}
else if (bytes_after != 0)
{
#ifdef WARNING
fprintf(stderr, "%s: Remote property bigger than maximum limits.\n", __func__);
#endif
}
else if (!ValidAtom(typeL))
{
#ifdef WARNING
fprintf(stderr, "%s: Failed to convert remote atom [%ld].\n", __func__,
(long int) type);
#endif
}
else if (nitems == 0)
{
#ifdef TEST
fprintf(stderr, "%s: Importing void property.\n", __func__);
#endif
import = True;
}
else if (property == nxagentAtoms[0]) /* NX_IDENTITY */
{
#ifdef WARNING
fprintf(stderr, "%s: not importing private [%ld][NXDARWIN].\n", __func__,
(long int) property);
#endif
}
else if (property == nxagentAtoms[5]) /* NX_CUT_BUFFER_SERVER */
{
#ifdef WARNING
fprintf(stderr, "%s: not importing private [%ld][NX_CUT_BUFFER_SERVER].\n", __func__,
(long int) property);
#endif
}
else if (property == nxagentAtoms[8]) /* NX_AGENT_SIGNATURE */
{
#ifdef WARNING
fprintf(stderr, "%s: not importing private [%ld][NX_AGENT_SIGNATURE].\n", __func__,
(long int) property);
#endif
}
else if (property == nxagentAtoms[9]) /* NXDARWIN */
{
#ifdef TEST
fprintf(stderr, "%s: not importing private [%ld][NXDARWIN].\n", __func__,
(long int) property);
#endif
}
else if (property == nxagentAtoms[15]) /* NX_SELTRANS_FROM_AGENT */
{
#ifdef TEST
fprintf(stderr, "%s: not importing private [%ld][NX_SELTRANS_FROM_AGENT].\n", __func__,
(long int) property);
#endif
}
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.
*/
wmState = *(WMState*)buffer;
WindowPtr 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, "%s: WARNING! Failed to convert remote window [%ld] importing property [%ld]"
" of type WM_STATE", __func__, (long int) wmState.icon, (long int) property);
#endif
}
}
else if (strcmp(typeS, "WM_HINTS") == 0)
{
nxagentWMHints 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, "%s: WARNING! Failed to look up remote icon pixmap [%d] from hint importing"
" property [%ld] type [%s] on window [%p].\n", __func__,
(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, "%s: WARNING! Failed to look up remote icon window [0x%x] from hint importing"
" property [%ld] type [%s] on window [%p].\n", __func__,
(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, "%s: WARNING! Failed to look up remote icon mask [0x%x] from hint importing"
" property [%ld] type [%s] on window [%p].\n", __func__,
(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, "%s: WARNING! Failed to look up remote window group [0x%x] from hint importing"
" property [%ld] type [%s] on window [%p].\n", __func__,
(unsigned int) wmHints.window_group,
(long int) property, typeS, (void *) pWin);
#endif
}
}
}
else if (strcmp(typeS, "ATOM") == 0)
{
Atom *atoms = malloc(nitems * sizeof(Atom));
CARD32 *input = (CARD32*) buffer;
if (atoms == NULL)
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! malloc() failed for '[%s]' - bailing out.\n", __func__, typeS);
#endif
return;
}
freeMem = True;
import = True;
output = (char *) atoms;
for (int i = 0; i < nitems; i++)
{
atoms[i] = nxagentRemoteToLocalAtom((XlibAtom)input[i]);
if (atoms[i] == None)
{
#ifdef WARNING
fprintf(stderr, "%s: WARNING! Failed to convert remote atom [%ld].\n", __func__,
(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, "%s: WARNING! malloc() failed for '[%s]' - bailing out.\n", __func__, 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, "%s: WARNING! Failed to look up remote window [0x%lx] importing property [%ld]"
" type [%s] on window [%p].\n", __func__,
(long int) input[i], (long int) property, typeS, (void*)pWin);
#endif
wind[i] = None;
}
}
}
if (import)
{
#ifdef TEST
fprintf(stderr, "%s: ChangeProperty on window [0x%x] property [%ld] type [%s]"
" nitems [%ld] format [%d]\n", __func__,
window, property, typeS, nitems, format);
#endif
ChangeWindowProperty(pWin, propertyL, typeL, format,
PropModeReplace, nitems, output, 1);
}
else
{
#ifdef TEST
fprintf(stderr, "%s: WARNING! Ignored ChangeProperty on window [0x%x] property [%ld] type [%s]"
" ntems [%ld] format [%d]\n", __func__,
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 property 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;
XlibAtom 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, "%s: Property [%ld] on Window [0x%x] to list, list size is [%d].\n", __func__,
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(XlibAtom property, WindowPtr pWin)
{
if (NXDisplayError(nxagentDisplay) == 1)
{
return;
}
struct nxagentPropertyRec *tmp = malloc(sizeof(struct nxagentPropertyRec));
if (tmp == NULL)
{
FatalError("%s: malloc() failed.", __func__);
}
#ifdef TEST
fprintf(stderr, "%s: Adding record Property [%ld] - Window [0x%x][%p] to list, list"
" size is [%d].\n", __func__, 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 notifications generated by an external
* client from those generated by our own requests.
*/
Bool nxagentNotifyMatchChangeProperty(void *p)
{
struct nxagentPropertyRec *first = nxagentPropertyList.first;
XPropertyEvent *X = p;
#ifdef TEST
fprintf(stderr, "%s: Property notify on window [0x%lx] property [%ld].\n", __func__,
X -> window, X -> atom);
if (first)
{
fprintf(stderr, "%s: First element on list is window [0x%x] property [%ld] list size is [%d].\n", __func__,
first -> window, first -> property, nxagentPropertyList.size);
}
else
{
fprintf(stderr, "%s: List is empty.\n", __func__);
}
#endif
if (first == NULL ||
X -> window != first -> window ||
X -> atom != first -> property)
{
return False;
}
nxagentRemovePropertyFromList();
return True;
}