927 lines
24 KiB
C
927 lines
24 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 "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 "Utils.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 void 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];
|
|
|
|
/*
|
|
* Careful! Do not change indices here! Some of those are referenced
|
|
* at other places via nxagentAtoms[index].
|
|
*/
|
|
static char *nxagentAtomNames[NXAGENT_NUMBER_OF_ATOMS + 2] =
|
|
{
|
|
"NX_IDENTITY", /* 0 */
|
|
/* NX_IDENTITY was used in earlier nx versions to communicate
|
|
the version to NXwin. Got dropped between nxagent 1.5.0-45
|
|
and 1.5.0-112. */
|
|
"WM_PROTOCOLS", /* 1 */
|
|
/* standard ICCCM Atom */
|
|
"WM_DELETE_WINDOW", /* 2 */
|
|
/* standard ICCCM Atom */
|
|
"WM_NX_READY", /* 3 */
|
|
/* nxagent takes the ownership of the selection with this name
|
|
to signal the nxclient (or any other watching program)
|
|
it is ready. This is only used if NXAGENT_ONSTART is defined.
|
|
We cannot enclose it in #ifdef here because we use the numeric
|
|
indices to this structure at multiple places. */
|
|
"MCOPGLOBALS", /* 4 */
|
|
/* used for artsd support. Only used if compiled with
|
|
NXAGENT_ARTSD */
|
|
"NX_CUT_BUFFER_SERVER", /* 5 */
|
|
/* this is the name of a property on nxagent's window on the
|
|
real X server. This property is used for passing clipboard
|
|
content from clients of the real X server to nxagent's clients
|
|
|
|
Unfortunately we cannot rename this to NX_SELTRANS_TO_AGENT
|
|
because nomachine's nxclient and nxwin are using this
|
|
Atom/selection for communication with the nxagent Atom. */
|
|
"TARGETS", /* 6 */
|
|
/* used to request a list of supported data formats from the
|
|
selection owner. Standard ICCCM Atom */
|
|
"TEXT", /* 7 */
|
|
/* one of the supported data formats for selections. Standard
|
|
ICCCM Atom */
|
|
"NX_AGENT_SIGNATURE", /* 8 */
|
|
/* this is used to set a property on nxagent's window if nxagent
|
|
is started with the fullscreen option set. Unsure, what this
|
|
is used for. */
|
|
"NXDARWIN", /* 9 */
|
|
/* this was an Atom in nxdarwin, nomachine's X server for MacOS. */
|
|
"CLIPBOARD", /* 10 */
|
|
/* Atom for the clipboard selection. PRIMARY is fixed in X11 but
|
|
CLIPBOARD is not. Standard ICCCM Atom. */
|
|
"TIMESTAMP", /* 11 */
|
|
/* used to request the time a selection has been owned. Standard
|
|
ICCCM Atom */
|
|
"UTF8_STRING", /* 12 */
|
|
/* one of the supported data formats for selections. Standard
|
|
ICCCM Atom */
|
|
"_NET_WM_STATE", /* 13 */
|
|
/* standard ICCCM Atom */
|
|
"_NET_WM_STATE_FULLSCREEN", /* 14 */
|
|
/* standard ICCCM Atom */
|
|
"NX_SELTRANS_FROM_AGENT", /* 15 */
|
|
/* this is the name of a property on nxagent's window on the real
|
|
X server. This property is used for passing clipboard content
|
|
from nxagent's clients to clients on the real X server */
|
|
"COMPOUND_TEXT", /* 16 */
|
|
/* one of the supported data formats for selections. Standard
|
|
ICCCM Atom */
|
|
"INCR", /* 17 */
|
|
/* incremental clipboard transfers. Standard
|
|
ICCCM Atom */
|
|
"MULTIPLE", /* 18 */
|
|
/* request selection in multiple formats at once. Standard
|
|
ICCCM Atom */
|
|
"DELETE", /* 19 */
|
|
/* request to delete selection. Standard ICCCM Atom */
|
|
"INSERT_SELECTION", /* 20 */
|
|
/* request to insert other selection. Standard ICCCM Atom */
|
|
"INSERT_PROPERTY", /* 21 */
|
|
/* request to insert content of property into selection. Standard
|
|
ICCCM Atom */
|
|
"SAVE_TARGETS", /* 22 */
|
|
/* request to save clipboard content to clipboard manager on
|
|
exit, see
|
|
https://www.freedesktop.org/wiki/ClipboardManager */
|
|
"TARGET_SIZES", /* 23 */
|
|
/* request to retrieve the sizes of the clipboard content in
|
|
various formats, see
|
|
https://www.freedesktop.org/wiki/ClipboardManager */
|
|
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(void)
|
|
{
|
|
/*
|
|
* 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()
|
|
{
|
|
/* FIXME: verbose is always false, there's no code to set it to true */
|
|
Bool verbose = False;
|
|
Bool windowManagerWasRunning = nxagentWMIsRunning;
|
|
|
|
startWMDetection();
|
|
|
|
XSync(nxagentDisplay, 0);
|
|
|
|
if (windowManagerWasRunning != nxagentWMIsRunning)
|
|
{
|
|
verbose = False;
|
|
}
|
|
|
|
finishWMDetection(verbose);
|
|
}
|
|
|
|
void nxagentInitAtoms()
|
|
{
|
|
/*
|
|
* 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 atom = MakeAtom(nxagentAtomNames[8], strlen(nxagentAtomNames[8]), 1);
|
|
|
|
if (atom == None)
|
|
{
|
|
#ifdef PANIC
|
|
fprintf(stderr, "%s: PANIC! Could not create [%s] atom.\n", __func__,
|
|
nxagentAtomNames[8]);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentInitAtoms: atom [%s] created with value [%d].\n",
|
|
nxagentAtomNames[8], atom);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int nxagentQueryAtoms(ScreenPtr pScreen)
|
|
{
|
|
static unsigned long atomGeneration = 1;
|
|
|
|
int num_of_atoms = NXAGENT_NUMBER_OF_ATOMS;
|
|
char *names[NXAGENT_NUMBER_OF_ATOMS];
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: Going to create the intern atoms on real display.\n", __func__);
|
|
#endif
|
|
|
|
nxagentPrintAtomMapInfo("nxagentQueryAtoms: Entering");
|
|
|
|
for (int 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, "%s: The nxagent has been reset with server %ld atom %ld.\n", __func__,
|
|
serverGeneration, atomGeneration);
|
|
|
|
fprintf(stderr, "%s: Forcing a sync to detect the window manager.\n", __func__);
|
|
#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, True);
|
|
|
|
/*
|
|
* 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 (int i = 0; i < num_of_atoms; i++)
|
|
{
|
|
fprintf(stderr, "%s: Created intern atom [%s] with id [%ld].\n", __func__,
|
|
names[i], nxagentAtoms[i]);
|
|
}
|
|
#endif
|
|
|
|
nxagentPrintAtomMapInfo("nxagentQueryAtoms: Exiting");
|
|
|
|
return 1;
|
|
}
|
|
|
|
#define NXAGENT_ATOM_MAP_SIZE_INCREMENT 256
|
|
|
|
typedef struct {
|
|
Atom local;
|
|
XlibAtom remote;
|
|
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, XlibAtom, const char*);
|
|
static AtomMap* nxagentFindAtomByRemoteValue(XlibAtom);
|
|
static AtomMap* nxagentFindAtomByLocalValue(Atom);
|
|
static AtomMap* nxagentFindAtomByName(char*, unsigned);
|
|
|
|
static void nxagentExpandCache(void)
|
|
{
|
|
privAtomMapSize += NXAGENT_ATOM_MAP_SIZE_INCREMENT;
|
|
|
|
AtomMap * newmap = realloc(privAtomMap, privAtomMapSize * sizeof(AtomMap));
|
|
|
|
if (newmap == NULL)
|
|
{
|
|
FatalError("nxagentExpandCache: realloc failed\n");
|
|
}
|
|
else
|
|
{
|
|
privAtomMap = newmap;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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, XlibAtom remote, const char *string)
|
|
{
|
|
char *s = strdup(string);
|
|
|
|
#ifdef WARNING
|
|
if (s == NULL)
|
|
{
|
|
/* we only warn here, because s being NULL ist not problem, it
|
|
will only result in NULL being stored in the privAtomMap, which
|
|
is perfectly legal. */
|
|
fprintf(stderr, "%s: Malloc failed.\n", __func__);
|
|
}
|
|
#endif
|
|
|
|
if (privLastAtom == privAtomMapSize)
|
|
{
|
|
/* will issue a fatal error, therefore no further check here */
|
|
nxagentExpandCache();
|
|
}
|
|
|
|
privAtomMap[privLastAtom].local = local;
|
|
privAtomMap[privLastAtom].remote = remote;
|
|
privAtomMap[privLastAtom].string = s;
|
|
privAtomMap[privLastAtom].length = s ? strlen(s) : 0;
|
|
|
|
privLastAtom++;
|
|
}
|
|
|
|
/*
|
|
* Clean up the atom map at nxagent reset, in order to cancel all the
|
|
* local atoms but still maintaining the Xserver values and the atom
|
|
* names. This is called from Dispatch()
|
|
*/
|
|
void nxagentResetAtomMap(void)
|
|
{
|
|
nxagentPrintAtomMapInfo("nxagentResetAtomMap: Entering");
|
|
|
|
for (unsigned int i = 0; i < privLastAtom; i++)
|
|
{
|
|
privAtomMap[i].local = None;
|
|
}
|
|
|
|
nxagentPrintAtomMapInfo("nxagentResetAtomMap: Exiting");
|
|
}
|
|
|
|
void nxagentFreeAtomMap(void)
|
|
{
|
|
for (unsigned int i = 0; i < privLastAtom; i++)
|
|
{
|
|
SAFE_free(privAtomMap[i].string);
|
|
}
|
|
|
|
SAFE_free(privAtomMap);
|
|
privLastAtom = privAtomMapSize = 0;
|
|
}
|
|
|
|
/*
|
|
* Init map.
|
|
* Initializing the atomNameList all in one.
|
|
*/
|
|
|
|
static void nxagentInitAtomMap(char **atomNameList, int count, Atom *atomsRet)
|
|
{
|
|
int list_size = count + privLastAtom;
|
|
|
|
nxagentPrintAtomMapInfo("nxagentInitAtomMap: Entering");
|
|
|
|
XlibAtom *atom_list = malloc((list_size) * sizeof(*atom_list));
|
|
char **name_list = malloc((list_size) * sizeof(char*));
|
|
|
|
if ((atom_list == NULL) || (name_list == NULL))
|
|
{
|
|
SAFE_free(atom_list);
|
|
SAFE_free(name_list);
|
|
FatalError("nxagentInitAtomMap: malloc failed\n");
|
|
}
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
{
|
|
name_list[i] = atomNameList[i];
|
|
atom_list[i] = None;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < privLastAtom; i++)
|
|
{
|
|
name_list[count + i] = (char *)privAtomMap[i].string;
|
|
atom_list[count + i] = None;
|
|
}
|
|
|
|
/*
|
|
* Ask X-Server for our Atoms
|
|
* ... if successful cache them too.
|
|
*/
|
|
|
|
int 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
|
|
|
|
SAFE_free(atom_list);
|
|
SAFE_free(name_list);
|
|
|
|
return;
|
|
}
|
|
|
|
for (unsigned int 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]);
|
|
}
|
|
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];
|
|
}
|
|
}
|
|
|
|
SAFE_free(atom_list);
|
|
SAFE_free(name_list);
|
|
|
|
nxagentPrintAtomMapInfo("nxagentInitAtomMap: Exiting");
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* If the nxagent has been reset, 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)
|
|
{
|
|
if (!ValidAtom(local))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < privLastAtom; i++)
|
|
{
|
|
if (local == privAtomMap[i].local)
|
|
{
|
|
return (privAtomMap + i);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static AtomMap* nxagentFindAtomByRemoteValue(XlibAtom remote)
|
|
{
|
|
if (remote == None || remote == BAD_RESOURCE)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < privLastAtom; i++)
|
|
{
|
|
if (remote == privAtomMap[i].remote)
|
|
{
|
|
return (privAtomMap + i);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static AtomMap* nxagentFindAtomByName(char *string, unsigned int length)
|
|
{
|
|
for (unsigned int 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 easier to read.
|
|
* I think this and the 2 .*Find.* are the only functions to look for performances.
|
|
*/
|
|
|
|
XlibAtom nxagentMakeAtom(char *string, unsigned int length, Bool Makeit)
|
|
{
|
|
/*
|
|
* Surely MakeAtom is faster than our nxagentFindAtomByName.
|
|
*/
|
|
|
|
Atom local = MakeAtom(string, length, Makeit);
|
|
|
|
if (!ValidAtom(local))
|
|
{
|
|
return None;
|
|
}
|
|
|
|
if (local <= XA_LAST_PREDEFINED)
|
|
{
|
|
return local;
|
|
}
|
|
|
|
AtomMap *current;
|
|
|
|
if ((current = nxagentFindAtomByLocalValue(local)))
|
|
{
|
|
/*
|
|
* Found cached by value.
|
|
*/
|
|
|
|
return current->remote;
|
|
}
|
|
else if ((current = nxagentFindAtomByName(string, length)))
|
|
{
|
|
/*
|
|
* Found cached by name.
|
|
* It means that nxagent has been reset,
|
|
* but not the xserver so we still have cached its atoms.
|
|
*/
|
|
|
|
current->local = local;
|
|
|
|
return current->remote;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We really have to ask the Xserver for it.
|
|
*/
|
|
|
|
/* FIXME: why is Makeit inverted here? */
|
|
XlibAtom remote = XInternAtom(nxagentDisplay, string, !Makeit);
|
|
|
|
if (remote == None)
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentMakeAtom: WARNING XInternAtom(.., %s, ..) failed.\n", string);
|
|
#endif
|
|
|
|
return None;
|
|
}
|
|
else
|
|
{
|
|
nxagentWriteAtom(local, remote, string);
|
|
|
|
return remote;
|
|
}
|
|
}
|
|
}
|
|
|
|
XlibAtom nxagentLocalToRemoteAtom(Atom local)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: entering\n", __func__);
|
|
#endif
|
|
|
|
if (!ValidAtom(local))
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: local [%d] is no valid - returning None\n", __func__, local);
|
|
#endif
|
|
return None;
|
|
}
|
|
|
|
/* no mapping required for built-in atoms */
|
|
if (local <= XA_LAST_PREDEFINED)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: local [%d] is < XA_LAST_PREDEFINED [%d]\n", __func__, local, XA_LAST_PREDEFINED);
|
|
#endif
|
|
return local;
|
|
}
|
|
|
|
AtomMap *current = nxagentFindAtomByLocalValue(local);
|
|
|
|
if (current)
|
|
{
|
|
#ifdef DEBUG
|
|
if (current->string)
|
|
fprintf(stderr, "%s: local [%d] -> remote [%d (%s)]\n", __func__, local, current->remote, current->string);
|
|
else
|
|
fprintf(stderr, "%s: local [%d] -> remote [%d] (no string cached)\n", __func__, local, current->remote);
|
|
#endif
|
|
|
|
return current->remote;
|
|
}
|
|
else
|
|
{
|
|
const char *string = NameForAtom(local);
|
|
|
|
/* False means "create Atom if it does not exist yet" */
|
|
XlibAtom remote = XInternAtom(nxagentDisplay, string, False);
|
|
|
|
if (remote == None)
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentLocalToRemoteAtom: WARNING XInternAtom failed.\n");
|
|
#endif
|
|
|
|
return None;
|
|
}
|
|
|
|
nxagentWriteAtom(local, remote, string);
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: local [%d (%s)] -> remote [%d]\n", __func__, local, string, remote);
|
|
#endif
|
|
|
|
return remote;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This is mainly used to simplify debug prints. It returns
|
|
* the string for a remote atom or NULL if atom is unknown/invalid
|
|
*
|
|
* The string must NOT be freed by the caller.
|
|
*/
|
|
const char *nxagentRemoteAtomToString(XlibAtom remote)
|
|
{
|
|
if (remote == None || remote == BAD_RESOURCE)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: remote [%d] is None or BAD_RESOURCE\n", __func__, remote);
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
/* no mapping required for built-in atoms */
|
|
if (remote <= XA_LAST_PREDEFINED)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: remote [%d] is <= XA_LAST_PREDEFINED [%d]\n", __func__, remote, XA_LAST_PREDEFINED);
|
|
#endif
|
|
|
|
/* simply use the builtin string that is the same on every X server */
|
|
return NameForAtom(remote);
|
|
}
|
|
|
|
AtomMap *current = nxagentFindAtomByRemoteValue(remote);
|
|
if (current)
|
|
{
|
|
return current->string;
|
|
}
|
|
else
|
|
{
|
|
/* fill up the cache */
|
|
Atom local = nxagentRemoteToLocalAtom(remote);
|
|
if (local != None)
|
|
{
|
|
current = nxagentFindAtomByRemoteValue(remote);
|
|
if (current)
|
|
{
|
|
return current->string;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
Atom nxagentRemoteToLocalAtom(XlibAtom remote)
|
|
{
|
|
if (remote == None || remote == BAD_RESOURCE)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: remote [%d] is None or BAD_RESOURCE\n", __func__, remote);
|
|
#endif
|
|
return None;
|
|
}
|
|
|
|
/* no mapping required for built-in atoms */
|
|
if (remote <= XA_LAST_PREDEFINED)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: remote [%d] is <= XA_LAST_PREDEFINED [%d]\n", __func__, remote, XA_LAST_PREDEFINED);
|
|
#endif
|
|
return remote;
|
|
}
|
|
|
|
AtomMap *current = nxagentFindAtomByRemoteValue(remote);
|
|
|
|
if (current)
|
|
{
|
|
if (!ValidAtom(current->local))
|
|
{
|
|
Atom 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;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (current->string)
|
|
fprintf(stderr, "%s: remote [%d] -> local [%d (%s)]\n", __func__, remote, current->local, current->string);
|
|
else
|
|
fprintf(stderr, "%s: remote [%d] -> local [%d]\n", __func__, remote, current->local);
|
|
#endif
|
|
|
|
return current->local;
|
|
}
|
|
else
|
|
{
|
|
char *string = XGetAtomName(nxagentDisplay, remote);
|
|
|
|
if (string)
|
|
{
|
|
Atom local = MakeAtom(string, strlen(string), True);
|
|
|
|
if (!ValidAtom(local))
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "%s: WARNING MakeAtom failed.\n", __func__);
|
|
#endif
|
|
|
|
local = None;
|
|
}
|
|
|
|
nxagentWriteAtom(local, remote, string);
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "%s: remote [%d (%s)] -> local [%d]\n", __func__, remote, string, local);
|
|
#endif
|
|
SAFE_XFree(string);
|
|
|
|
return local;
|
|
}
|
|
|
|
#ifdef WARNING
|
|
fprintf(stderr, "%s: WARNING failed to get name from remote atom.\n", __func__);
|
|
#endif
|
|
|
|
return None;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
static void nxagentPrintAtomMapInfo(char *message)
|
|
{
|
|
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 (unsigned int i = 0; i < privLastAtom; i++)
|
|
{
|
|
fprintf(stderr, "[%5.1d] local: %6.1u - remote: %6.1u - [%p] %s\n", i,
|
|
privAtomMap[i].local,
|
|
privAtomMap[i].remote,
|
|
privAtomMap[i].string, validateString(privAtomMap[i].string));
|
|
}
|
|
|
|
fprintf(stderr, "---------------------------------------------\n");
|
|
}
|
|
|
|
#endif
|