What is an atom in X11?

 

An atom in X11, is of type Atom, which is defined in the <X11/Xatom.h> header, as :

typedef unsigned long Atom;		/* Also in Xdefs.h */

An atom is 32 bits, the reason, that long was chosen, is because the C standard, defines it, as having a minimum length of 32 bits. This being said, an atom is used, as a way, to identify a string, to be, or which is stored, at the server.

The process of storing a string on the server, and getting back an atom for it, is called interning.

Interning an atom

There are two functions, which can do atom interning , which in other words is, getting an identifier, for a string stored on a server, and they are : XInternAtom and XInternAtoms.

The XInternAtom function, has the following signature:

Atom XInternAtom 
                 (Display* display, 
                  char *atom_string_name, 
                  Bool only_if_exists ); 

So the function, takes as arguments: the display, which is simply a reference to a connection, established with the X server, a string, which can be thought of, as the name of the atom, and a boolean value, named only_if_exists. The function returns an atom, identifying the passed string.

if only_if_exists, is set to true, this means, that if the string does not already exist on the server, it is not going to be stored there, so this function will return a None value.

if only_if_exists, is set to false, and the string does not exist on the server, then it is going to be stored, and an atom is returned for that string. if the string does exist, then the atom identifying it, is returned.

The value of None, is defined in the <X11/Xatom.h> header, as :

#define None                 0L	/* universal null resource or null atom */

The XInternAtoms function, has the following signature:

Status XInternAtoms
                 (Display* display, 
                  char** atom_string_names, 
                  int count, 
                  Bool only_if_exists, 
                  Atom* atoms_return ); 

The passed in arguments, are the display, which is a reference, to a connection to the server, atom_string_names, which is a pointer to a C string , count, which is the number of strings, pointed to by, atom_string_names, only_if_exists, which has the same meaning, as the one described, in the XInternAtom function, and finally atoms_return, which is an array, which will be filled, with the atoms, identifying each passed string.

If not all passed strings, have an atom allocated to them, then the value of the returned Status , is a zero value, which symbolizes error, otherwise, and if each passed string, had an atom allocated to it, then the Status, has a non zero value.

Both of XInternAtom and XInternAtoms functions, can cause a BadAlloc error, if the server, was not able to allocate memory, and they can cause a BadValue error, which happens, if an argument numerical value, is outside of the range, accepted by the server.

The allocated atom, will remain defined, until all the connections, to the server are closed, even if the client who has created this atom, exits.

An example of using both the XInternAtom and XInternAtoms functions is:

#include <X11/Xlib.h>

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>


int
        main
            (int argc , char* argv[ ] ){

    Display* display;
    char* connection_string = NULL;
    display = XOpenDisplay (connection_string  );
    if (display == NULL ){
        fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" :  connection_string );
        exit (EXIT_FAILURE );}

    char* string_life = "Life is cool";
    Atom atom_life;
    atom_life = XInternAtom (display, string_life, false );
    printf ("atom_life is : %lu\n", atom_life );

    int num_string =3;
    char* strings [ ] = {"First string", "Second string", "Third string" };
    Atom atom [num_string ];
    int status = XInternAtoms (display, //The connection
                    strings, //The strings
                    num_string, // count of strings
                    false,  // only_if_exists
                    atom );
    if (status == 0 ){
        fprintf (stderr, "Error: XInternAtoms \n" );
        exit (EXIT_FAILURE );}

    for (int i = 0; i < num_string; i++ )
        printf ("atom [%d ] is %lu\n", i, atom [i ] );

     exit (EXIT_SUCCESS ); }
/* Output:
atom_life is : 343
atom [0 ] is 344
atom [1 ] is 345
atom [2 ] is 346
*/

Getting an atom string value

As explained earlier, an atom is simply an integral value, with which a server has associated a string, so you can think of the string, as the atom name.

This being said, what if we wanted to do the inverse, so having an atom, we want its name. Well to do that, there are two functions, that can be used : XGetAtomName and XGetAtomNames.

The signature of the XGetAtomName function is :

char* XGetAtomName
           (Display* display, 
            Atom atom );

The arguments to the the XGetAtomName function, are the display, which is just a reference , to the connection to the server, and the atom, for which you want its name returned.

The function returns, the string associated with the passed in atom. This string can be freed, once done using it, by using the XFree function.

The XGetAtomNames function, has the following signature:

Status XGetAtomNames
            (Display* display, 
             Atom* atoms, 
             int count, 
             char** names_return ); 

The arguments are, the display, which is a reference, to the connection to the server, atoms, which is a pointer to an Atom, so this is a pointer to the atoms, that you wish, to get their string representations, count, which is the number of atoms, pointed by atoms, names_return , which is a pointer to an array of strings, in which the gotten atom names, are stored.

The value returned by XGetAtomNames, is non zero, if the function was able to get a name, for each of the passed in atoms, and a zero value is returned, if the function, was not able to get a name, for each of the passed in atoms.

Both of the XGetAtomName, and XGetAtomNames functions, can cause a BadAtom error, if an atom pointed by atoms, is not recognized by the server, as referring to a name, stored on the server.

An example of using both the XGetAtomName, and XGetAtomNames functions, is:

#include <X11/Xlib.h>
#include <X11/Xatom.h>

#include <stdio.h>
#include <stdlib.h>

 
int
        main
            (int argc , char* argv[ ] ){


    Display* display;
    char* connection_string = NULL;
    display = XOpenDisplay (connection_string  );
    if (display == NULL ){
        fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" :  connection_string );
        exit (EXIT_FAILURE );}

    char* atom_name;
    atom_name = XGetAtomName (display, XA_PRIMARY );

    printf ("Name of atom XA_PRIMARY %lu is : %s\n", XA_PRIMARY, atom_name );
    XFree (atom_name );


    int num_atoms = 3;
    char* atom_names [num_atoms ];
    Atom atoms [ ] = {XA_STRING, XA_COLORMAP, XA_WM_SIZE_HINTS };
    int status = XGetAtomNames (display, 
                                atoms, 
                                num_atoms, 
                                atom_names ); 

    if (status == 0 ){
        fprintf (stderr, "Error: XGetAtomNames \n" );
        exit (EXIT_FAILURE );}

    printf ("Name of atom XA_STRING %lu is : %s\n", XA_STRING, atom_names [0 ] );
    printf ("Name of atom XA_COLORMAP %lu is : %s\n", XA_COLORMAP, atom_names [1 ] );
    printf ("Name of atom XA_WM_SIZE_HINTS %lu is : %s\n", XA_WM_SIZE_HINTS, atom_names [2 ] );

    exit (EXIT_SUCCESS );}
/* Output:
Name of atom XA_PRIMARY 1 is : PRIMARY
Name of atom XA_STRING 31 is : STRING
Name of atom XA_COLORMAP 7 is : COLORMAP
Name of atom XA_WM_SIZE_HINTS 41 is : WM_SIZE_HINTS
*/

In the previous example, some predefined atoms, in the <X11/Xatom.h> header, were used, these are just some atoms, to which the server associates some names.

For the predefined atoms, instead of using the XGetAtomName, or XGetAtomNames functions, to get their associated strings, you could just remove, the XA_ part, to guess what the associated string is.

So for example, if the atom was defined in <X11/Xatom.h>, as XA_COLORMAP, then the string associated with it, would be COLORMAP .