What is a property in X11?

 

In X11, a property simply has a name, a type, a format, a value, and is associated with a window.

There is a set of functions, provided by X11, which allows manipulating a property, and they are : XChangeProperty, XGetWindowProperty, XDeleteProperty, XListProperties, XRotateWindowProperties.

In the next sections of this tutorial, we will be discussing these functions, and this will make clearer what a property really is.

XChangeProperty : Create or update a property

The XChangeProperty function, is used to create a property, or to update its value.

Once a property has been created or updated, the XChangeProperty function, will generate a PropertyNotify event, which indicates, that a property associated with this window, has been changed.

The signature of the XChangeProperty function is:

  1. XChangeProperty
  2.      (Display* display,
  3.       Window window,
  4.       Atom property_name,
  5.       Atom property_type,
  6.       int format,
  7.       int operation_mode,
  8.       unsigned char* property_data,
  9.       int number_elements_data )

display

display, is just a reference, to a connection to the server, a connection can be gotten, by using the XOpenDisplay function.

window

window is the id of the window, to which the property will be associated. A window is where your application, is going to do the drawing, and is created using either of, the XCreateSimpleWindow, or the XCreateWindow functions. Both of these functions, return the id of the created window.

The window id, has a type of Window, which is defined as typedef XID Window;, where XID is defined as typedef unsigned long XID; .

property_name

property_name , is of type atom. An atom , is an integral value, as in 1 or 2, which uniquely identify a string, any string, to be, or which is stored on the server. An atom is 32 bits.

So the idea is that an atom, is used in function calls, instead of a string, to minimize data transfer.

This being said, the property_name , is actually a string, which is stored on the server, and which has an atom , meaning an integral value, associated with it. To create an atom from a string, and to get a string from an atom, is explained in this tutorial .

This being said, there are some predefined property names, such as WM_COMMAND, as in, this property is named WM_COMMAND, or WM_ICON_NAME , or RESOURCE_MANAGER … which are stored on the server.

These predefined property names, are there to be used, for example, the window manager, will query a window, for a property named WM_HINTS, in order to identify, the window icon.

This being said, a property can be used for inter process, and inter windows communication.

An application can create a property, associate it with any window, even if that window, was not created by it, and store data into it, and any other application, can read properties, which are associated with any window, and can subscribe to the property change notify event, in order to be notified, when this property has been changed.

This being said, an application can also define, its own property names, and property types.

property_type

property_type , is of type atom, so as described earlier, a property_type, is a string stored on the server, and which has an atom associated with it. This atom is used in function calls.

Some predefined property types, also exist on the server, for example XA_WM_HINTS, is an atom, which is defined as #define XA_WM_HINTS ((Atom) 35), in the <X11/Xatom.h> header.

The <X11/Xatom.h> header, contains some predefined atoms, associated with strings, stored on the server, the strings are used, for example, for property names, property types, font properties …

To get the string, associated with these predefined atoms, you can use the XGetAtomName function, or you can just remove the XA_ part. So for example, the atom XA_WM_HINTS , is associated with the string WM_HINTS, which is stored on the server.

The WM_HINTS string, is used as both a name, and a type, for a property. The type is actually a structure, the structure XWMHints, which is defined as follows:

  1. typedef struct {
  2.     long flags;
  3.     Bool input;
  4.     int initial_state;
  5.     Pixmap icon_pixmap;
  6.     Window icon_window;
  7.     int icon_x;
  8.     int icon_y;
  9.     Pixmap icon_mask;
  10.     XID window_group;} XWMHints;

Other examples of a property types, are the string POINT, which is associated with the atom XA_POINT, and which is actually the structure :

  1. typedef struct {
  2.     short x, y;
  3. } XPoint;

This being said, knowing the type of a property, you can interpret its data.

format

format , is of type int, and it must be one of the three values, 8, 16, or 32.

A property has data, the format represents, how many bits, a unit of data, is formed of, so a unit of data, can be formed of, 8, 16, or 32 bits.

If the format specified is 8, then the property data, must be a char array, if it is 16, then the property data, must be, a short array, and if it is 32, then the property data, must be a long array.

Why long you might ask, for 32 bits? Simply because, int is defined by the C standard, as having a minimum of 16 bits, and long, as having a minimum of 32 bits. So whatever what long actually is, so even if it is 64 bits on your client, the server handles, the data as 32 bits. You can check the example for XGetWindowProperty, in the next section, to understand this more.

The data format, is mainly related to, little and big endian, which is how bits are stored into a computer, like is the most significant bit stored first, or last?

A property is stored on the server, hence its data is stored on the server, this being said, the endianness of the server, can be different from that of the client, hence it is important to specify the format correctly, as such the library would handle, the conversion between client and server endianness automatically.

operation_mode

operation_mode , is of type int, and it can take one of three values, defined in the <X11/X.h> header, and which are:

PropModeAppend , is defined as #define PropModeAppend 2, so basically the newly sent data, is appended, to the old data, and the data type and format, must match the old ones, or else, a BadMatch error is generated.

PropModePrepend , is defined as #define PropModePrepend 1, in this case, the newly sent data, is prepended, to the old data, and the type and format, of the new data, must match, the old ones, or a BadMatch error is generated.

PropModeReplace , is defined as #define PropModeReplace 0, the old data is discarded, and replaced with the new data, having the passed in format, and data type.

property_data

property_data , is of type unsigned char*, so basically, this is just a pointer to the data, that you want to be stored in this property.

number_elements_data

number_elements_data , is of type int, this is the number of units, so the number of units of, 8 or 16 or 32 bits data, which is being sent.

Example

In this example, the XChangeProperty method, is used to set a property named WM_NAME. A property with such a name, tells the window manager, that its data, is to be used, as the title, for the window, the window being a top level window.

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

  3. #include <stdbool.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>

  7. int
  8.         main
  9.             (int argc , char* argv[ ] ){

  10.     // get a connection to the server
  11.     char* connection_string = NULL;
  12.     Display* display;
  13.     display =  XOpenDisplay (connection_string  );
  14.     if (display == NULL ){
  15.         fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" :  connection_string );
  16.         exit (EXIT_FAILURE );}

  17.     // create a top level window
  18.     Window top_level_window;
  19.     top_level_window = XCreateSimpleWindow (
  20.         display ,
  21.         XDefaultRootWindow (display ), //parent window
  22.             // set the parent of top_level_window to the root window
  23.         0, //x position
  24.         0, //y position
  25.         300, //width
  26.         300, //height
  27.         0, //border width
  28.         0xFFFFFFFF , //border color
  29.         0xFF112233 /*background color .*/ );

  30.     XChangeProperty (display, //The connection
  31.         top_level_window, //The window
  32.         XA_WM_NAME, //atom, Property name
  33.         XA_STRING, //atom, Property type
  34.         8, //Property format
  35.         PropModeAppend, //Property mode
  36.         (unsigned char *) "Hey world", //Property data
  37.         strlen ("Hey world") ); //Number of data units

  38.     XSelectInput (display, top_level_window, ExposureMask );
  39.     //select the event, we want to handle
  40.     //In this case, the window being exposed

  41.     XMapWindow (display, top_level_window );
  42.     //Register a window to be
  43.     //exposed later on.

  44.     XEvent xevent;
  45.     while (true ){ //handle events
  46.         XNextEvent (display, &xevent );
  47.         switch (xevent .type ){
  48.             case Expose:
  49.         default:
  50.             break; }}

  51.     XCloseDisplay(display);
  52.     return 0;}

Errors that can be caused by the function

The XChangeProperty function, can cause a BadWindow error, if the window is not recognized, by the server, as being defined.

It can also cause a BadAtom error, if the atom is not valid, hence undefined on the server.

A BadMatch error, is generated, as explained earlier, when for example, you specify a mode of PropModeAppend, or PropModePrepend, and the type and format of the new data, do not match those of the old data.

A BadValue error, is generated, if a numerical value, is not within the required range.

A BadAlloc error, is generated, when the server is not able, to allocate, the requested memory.

XGetWindowProperty : Retrieve a property

What is XGetWindowProperty ?

As explained earlier, a window can have a property, a property has a name, a type, a format, and data, hence the aim of this function is to enable us, to retrieve all information, related to a property, so its type, its format, its data.

Function signature ?

The signature of the XGetWindowProperty function is:

  1. int XGetWindowProperty
  2.     (Display* display,
  3.      Window window,
  4.      Atom  property_name,
  5.      long data_offset_32,
  6.      long data_length_32,
  7.      Bool delete,
  8.      Atom requested_property_type,
  9.      Atom* returned_property_type,
  10.      int* returned_property_format,
  11.      unsigned long* returned_number_data_units,
  12.      unsigned long* number_of_bytes_remaining_after_return,
  13.      unsigned char** retrieved_data );
  • Display, is a reference to a connection to the server.
  • window is a window, for which, you want to get the named property.
  • property_name, is an atom, identifying, the name of the property, for which information, and data is to be retrieved.

    If property_name, is not valid, for the specified window, then the delete argument is ignored, the *returned_property_type, is set to the value None, which is defined as #define None 0L, in the <X11/Xatom.h> header, *returned_property_format is set to 0, and *number_of_bytes_remaining_after_return, is also set to 0.

    So in other words, the request for information, for this property, has failed, hence its important, to set a property name, correctly.

  • data_offset_32 is an offset, which is a multiple of 32, as in 32 bits. For example, it can be 0, so the offset is 0, it can be 1, so the offset is 32, it can be 2, so the offset is 64

    The offset, is calculated from the start of the data, associated with this property, so in other words, it is from this offset, that the property data will be retrieved.

    If the offset, is larger than the number of bytes, for this property data, than this will generate, a BadValue error.

  • data_length_32, is the number of 32 bits, block of data, that you wish to retrieve.

    If you pass in, a data length, which is larger, than the number of remaining bytes of data, then data length is set to, the number of remaining bytes of data.

    if data_length_32, is set to a negative value, then this will generate, a BadValue error.

  • delete if true, means that this property, is going to be deleted, if and only if number_of_bytes_remaining_after_return is 0 .

    If the property is deleted, then a PropertyNotify event, is generated, for the window, associated with this property.

  • property_type_requested is the requested type of the property .

    If the property does exist on the window, but its type does not match the requested type, then it is like querying the property, for its information, so what is going to happen is that, the delete argument is ignored, the returned_property_type, will be a reference to the actual property type, the returned_property_format will be a reference to the actual property format, and number_of_bytes_remaining_after_return, will be a reference to the number of bytes of data, for this property.

    If the type does match, or if it is set to the value AnyPropertyType , then all the values to be returned are set, the *returned_property_type, is set to the actual property type, the *returned_property_format is set to the actual property format, *returned_number_data_units is set to the number of units, as defined in property format, as in 8 or 16 or 32, that have been returned, *number_of_bytes_remaining_after_return, is set, to the number of bytes, remaining in the property data, after the returned data, and *retrieved_data is a reference to the retrieved data.

  • property_type_returned, is a reference, to the actual type of the property, as the server sees it.
  • property_format_returned, is a reference, to the actual format, of the data property, so it can be one of, 8, 16, or 32 bit.
  • number_units_data_returned, is a reference, to the number of 8 or 16 or 32 bits, which is the format of the data, that is returned.
  • number_of_bytes_remaining_after_return , is a reference, to the number of bytes remaining, after having gotten, the requested data.
  • retrieved_data, is of type unsigned char** , so this means, that you provide the address, of an unsigned char*.

    The library will allocate memory, to the property data, returned by the server, and will make your passed in pointer, point to the first element, of this memory. It is your job, to free this memory, once done using it, using XFree .

    If the property data format, is 8 bits, then the memory pointed, by your pointer, will be of type char , if the property data format is 16 bits, then your pointer, is pointing to a memory of type short, and if it is 32 bits, then your pointer is pointing to a memory, of type long.

    The data which has been retrieved, is always padded with a zero byte.

The function, returns the value Success, defined in the header <X11/Xlib.h> as #define Success 0, on success.

Example

In the following example, a property with an invalid name, is first gotten, and after that, all the data, related to a property, with a valid name, is retrieved .

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

  3. #include <stdbool.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>

  7. int
  8.         main
  9.             (int argc , char* argv[ ] ){

  10.     // get a connection to the server
  11.     char* connection_string = NULL;
  12.     Display* display;
  13.     display =  XOpenDisplay (connection_string  );
  14.     if (display == NULL ){
  15.         fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" :  connection_string );
  16.         exit (EXIT_FAILURE );}


  17.     // create a top level window
  18.     Window top_level_window;
  19.     top_level_window = XCreateSimpleWindow (
  20.         display ,
  21.         XDefaultRootWindow (display ), //parent window
  22.             // set the parent of top_level_window to the root window
  23.         0, //x position
  24.         0, //y position
  25.         300, //width
  26.         300, //height
  27.         0, //border width
  28.         0xFFFFFFFF , //border color
  29.         0xFF112233 /*background color .*/ );


  30.     /*Declare the values, to be returned
  31.         by a call to the XGetWindowProperty
  32.         function. */
  33.     Atom returned_property_type;
  34.     int returned_property_format;
  35.     unsigned long returned_number_data_units;
  36.     unsigned long number_of_bytes_remaining_after_return;
  37.     long* retrieved_data;


  38.     //Getting a property with an invalid name
  39.     int status = XGetWindowProperty (display, //The connection
  40.                     top_level_window, //The window
  41.                     XA_WM_NAME, //The property name
  42.                     0, //offset in 32 bits
  43.                     1, //number of elements in 32 bits
  44.                     False, //delete
  45.                     XA_INTEGER, //requested_property_type
  46.                     &returned_property_type,  //returned_property_type
  47.                     &returned_property_format, //returned_property_format
  48.                     &returned_number_data_units, //returned_number_data_units
  49.                     &number_of_bytes_remaining_after_return, //number_of_bytes_remaining_after_return
  50.                     (unsigned char** ) &retrieved_data /*retrieved_data */ );

  51.     printf("Results of getting a property, with an invalid name: \n" );
  52.     printf("\tstatus is : %d\n", status );
  53.     /*If returned_property_type is None,
  54.         and both of returned_property_format
  55.         and returned_number_data_units are
  56.         0, then the property name is
  57.         invalid.*/
  58.     printf("\treturned_property_type is : %lu\n", returned_property_type );
  59.     printf("\treturned_property_format is : %d\n", returned_property_format );
  60.     printf("\treturned_number_data_units is : %lu\n\n\n", returned_number_data_units );
  61.     /* Output:
  62.     Results of getting a property, with an invalid name:
  63.         status is : 0
  64.         returned_property_type is : 0
  65.         returned_property_format is : 0
  66.         returned_number_data_units is : 0 */


  67.     //Create an atom for a string
  68.     //which will be used, as our
  69.     //own property name.
  70.     Atom my_prop_atom = XInternAtom (display, "MY_PROPERTY", false );
  71.     int my_prop_data_len = 5;
  72.     long my_prop_data [ ] = {4294967297, 5, 6, 8, 10 };

  73.     //Define a property, on the
  74.     //top level window.
  75.     XChangeProperty (display, //The connection
  76.         top_level_window, //The window
  77.         my_prop_atom, //atom, Property name
  78.         XA_INTEGER, //atom, Property type
  79.         32, //Property format
  80.         PropModeAppend, //Property mode
  81.         (unsigned char *) my_prop_data, //Property data
  82.         my_prop_data_len ); //Number of data units


  83.     printf("Results of getting a property, with a valid name: \n" );
  84.     long offset = 0;
  85.     long length = 1;
  86.     do{
  87.         status = XGetWindowProperty (display, //The connection
  88.                         top_level_window, //The window
  89.                         my_prop_atom, //The property name
  90.                         offset, //offset in 32 bits
  91.                         length, //number of elements in 32 bits
  92.                         False, //delete
  93.                         XA_INTEGER, //requested_property_type
  94.                         &returned_property_type,  //returned_property_type
  95.                         &returned_property_format, //returned_property_format
  96.                         &returned_number_data_units, //returned_number_data_units
  97.                         &number_of_bytes_remaining_after_return, //number_of_bytes_remaining_after_return
  98.                         (unsigned char** ) &retrieved_data /*retrieved_data */ );

  99.         printf("\tstatus is : %d\n", status );
  100.         printf("\treturned_property_type is : %lu\n", returned_property_type );
  101.         printf("\treturned_property_format is : %d\n", returned_property_format );
  102.         printf("\treturned_number_data_units is : %lu\n", returned_number_data_units );
  103.         printf("\tnumber_of_bytes_remaining_after_return is : %lu\n", number_of_bytes_remaining_after_return );
  104.         printf("\tretrieved property data is: %ld\n\n", *retrieved_data );
  105.         offset++;
  106.         XFree (retrieved_data );
  107.     }while (number_of_bytes_remaining_after_return != 0 );
  108.     /* Output:
  109.     Results of getting a property, with a valid name:
  110.         status is : 0
  111.         returned_property_type is : 19
  112.         returned_property_format is : 32
  113.         returned_number_data_units is : 1
  114.         number_of_bytes_remaining_after_return is : 16
  115.         retrieved property data is: 1

  116.         status is : 0
  117.         returned_property_type is : 19
  118.         returned_property_format is : 32
  119.         returned_number_data_units is : 1
  120.         number_of_bytes_remaining_after_return is : 12
  121.         retrieved property data is: 5

  122.         status is : 0
  123.         returned_property_type is : 19
  124.         returned_property_format is : 32
  125.         returned_number_data_units is : 1
  126.         number_of_bytes_remaining_after_return is : 8
  127.         retrieved property data is: 6

  128.         status is : 0
  129.         returned_property_type is : 19
  130.         returned_property_format is : 32
  131.         returned_number_data_units is : 1
  132.         number_of_bytes_remaining_after_return is : 4
  133.         retrieved property data is: 8

  134.         status is : 0
  135.         returned_property_type is : 19
  136.         returned_property_format is : 32
  137.         returned_number_data_units is : 1
  138.         number_of_bytes_remaining_after_return is : 0
  139.         retrieved property data is: 10 */

  140.     XSelectInput (display, top_level_window, ExposureMask );
  141.     //select the event, we want to handle
  142.     //In this case, the window being exposed

  143.     XMapWindow (display, top_level_window );
  144.     //Register a window to be
  145.     //exposed later on.

  146.     XEvent xevent;
  147.     while (true ){ //handle events
  148.         XNextEvent (display, &xevent );
  149.         switch (xevent .type ){
  150.             case Expose:
  151.         default:
  152.             break; }}

  153.     XCloseDisplay(display);
  154.     return 0;}

Errors that can be caused by the function

This function can cause a BadAtom error, if a passed atom, is not identified by the server. It can also cause a BadValue error, if a numerical value, for an argument, is not within a required range, and finally, it can cause a BadWindow error, if a window id, is not identified by the server.

XListProperties : List window properties

What is XListProperties ?

The XListProperties function, can be used, to list the properties of a window.

The signature of the XListProperties function, is:

  1. Atom* XListProperties
  2.     (Display* display,
  3.      Window window,
  4.      int* number_returned_properties )

display is a reference, to a connection to the server. The window is the id of a window, which properties are to be retrieved. A BadWindow error, is generated, if the window id is not valid. number_returned_properties, is a reference, to the number of properties, which are returned.

If no properties are defined for this window, then the XListProperties function, will return NULL, otherwise, it will return a pointer, to the first element, of an array of atoms, which size is referenced, by number_returned_properties . In other words, you can loop through this array, in order to check the details for each property. Once done using, the returned pointer, it can be freed using XFree.

Another way of getting a window property, is by using the xprop utility, so you just execute the xprop command, and click on a window, which you want its properties displayed.

  1. $ xclock &
  2. # Launch the xclock
  3. # program.

  4. $ xprop
  5. # after clicking on xclock
  6. # the following is displayed
  7. WM_STATE(WM_STATE):
  8.                 window state: Normal
  9.                 icon window: 0x0
  10. _NET_WM_PID(CARDINAL) = 5208
  11. _WINDOWSWM_NATIVE_HWND(INTEGER) = 2689576, 0
  12. WM_PROTOCOLS(ATOM): protocols  WM_DELETE_WINDOW
  13. WM_CLIENT_LEADER(WINDOW): window id # 0x80000a
  14. WM_LOCALE_NAME(STRING) = "en_US.UTF-8"
  15. WM_CLASS(STRING) = "xclock", "XClock"
  16. WM_HINTS(WM_HINTS):
  17.                 Client accepts input or input focus: False
  18.                 Initial state is Normal State.
  19.                 bitmap id # to use for icon: 0x800001
  20.                 bitmap id # of mask for icon: 0x800003
  21. WM_NORMAL_HINTS(WM_SIZE_HINTS):
  22.                 program specified size: 164 by 164
  23.                 window gravity: NorthWest
  24. WM_CLIENT_MACHINE(STRING) = "DSKTP-TOAPK1I"
  25. WM_COMMAND(STRING) = { "xclock" }
  26. WM_ICON_NAME(STRING) = "xclock"
  27. WM_NAME(STRING) = "xclock"

xprop can also be used to set, or remove, a window’s property.

Example

In this example, the properties of the root window, have their property names, and their related atom numbers, printed.

  1. #include <X11/Xlib.h>

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

  4. int
  5.         main
  6.             (int argc , char* argv[ ] ){

  7.     // get a connection to the server
  8.     char* connection_string = NULL;
  9.     Display* display;
  10.     display =  XOpenDisplay (connection_string  );
  11.     if (display == NULL ){
  12.         fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" :  connection_string );
  13.         exit (EXIT_FAILURE );}

  14.     //List the properties of the root window
  15.     Atom* root_window_properties;
  16.     int number_returned_properties;
  17.     root_window_properties = XListProperties (display, //The display
  18.                                               DefaultRootWindow (display), //The root window
  19.                                               &number_returned_properties ); //The number of returned properties.

  20.     if (root_window_properties != NULL ){
  21.         printf ("atom\tname\n");
  22.         for (int i = 0; i < number_returned_properties; i++ ){
  23.             printf("%4lu\t%4s\t\n", root_window_properties [i ], XGetAtomName (display, root_window_properties[i ] ));}}
  24.     XCloseDisplay(display);
  25.     return 0;}
  26. /* Output:
  27. atom    name
  28.  241    __NET_DESKTOP_NAMES
  29.  240    _NET_NUMBER_OF_DESKTOPS
  30.  239    _NET_CURRENT_DESKTOP
  31.  243    _NET_SUPPORTED
  32.   38    WM_ICON_SIZE
  33.  232    _XKB_RULES_NAMES
  34. */

XDeleteProperty : Delete a property

Overview

A property can be created, updated, or read, by any client, on any window. A property life time, is not tied, to the client who has created it, but to the window hosting it, hence even, if the client who has created a window is destroyed, the property stays alive, until the window, it is associated with, is destroyed.

If a window is deleted, all its properties are deleted, and if a server is reset, all the properties are deleted.

Additionally a property can be deleted explicitly, as described earlier, using the XGetWindowProperty function, besides that, a property can also be deleted explicitly, by using the XDeleteProperty function.

The signature of the XDeleteProperty function, is :

  1. XDeleteProperty
  2.     (Display* display,
  3.      Window window,
  4.      Atom property );

display is a reference, to a connection to the server, window , is the id of the window, to delete its property, property , is an atom, identifying the property to be deleted.

If the window, and property are defined, and the property belongs to the window, the property is deleted, and a PropertyNotify event for the window is generated.

Errors that can arise, from using this function, are BadAtom, if the server does not know about the atom, and BadWindow, if the server does not know about the window.

Example

In this example, a property is created on the root window, and later on it is deleted using the XDeleteProperty function.

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

  3. #include <stdbool.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>

  7. int
  8.         main
  9.             (int argc , char* argv[ ] ){

  10.     // get a connection to the server
  11.     char* connection_string = NULL;
  12.     Display* display;
  13.     display =  XOpenDisplay (connection_string  );
  14.     if (display == NULL ){
  15.         fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" :  connection_string );
  16.         exit (EXIT_FAILURE );}


  17.     Atom atom = XInternAtom (display, "a_property_name", false );

  18.     XChangeProperty (display, //The connection
  19.         DefaultRootWindow (display ), //The window
  20.         atom, //atom, Property name
  21.         XA_STRING, //atom, Property type
  22.         8, //Property format
  23.         PropModeReplace, //Property mode
  24.         (unsigned char *) "Property data", //Property data
  25.         strlen ("Property data" ) ); //Number of data units

  26.     XDeleteProperty(
  27.       display,
  28.       DefaultRootWindow(display),
  29.       atom );


  30.     XCloseDisplay(display);
  31.     return 0;}

After compiling, and running the program, and to check if the created property, was successfully deleted, you can use xprop, on the root window, and the result should be empty.

  1. $ xprop.exe -root | grep a_property_name

XRotateWindowProperties : Circular rotation of properties values

what is XRotateWindowProperties ?

As the name of this function implies, it is used to rotate the values, of some properties, which are placed in an array, in a circular manner.

To explain it better, let us start, by defining the XRotateWindowProperties function signature:

  1. XRotateWindowProperties
  2.     (Display* display,
  3.      Window window,
  4.      Atom* properties,
  5.      int number_of_properties,
  6.      int  number_of_positions );

display, is a reference, to a connection to the server, window is the id of the window, which has some properties, which values are to be rotated, properties is an array of atoms, indicating the window properties, to be rotated, number_of_properties, is the number of properties, which are stored in the array. number_of_positions, is by how much, you are rotating each individual value.

In other words, given a property, at an array index, you subtract from its index, the number_of_positions, and you take its modulo, with relation to the number_of_properties, in order to know the index of the property, that it will take its value.

As an example, if the number_of_positions is 1, and the number_of_properties is 5, then the property at index 0, will take the value, of the property at index 0 - 1 % 5 = 4 .

And if the number_of_positions is -1, and the number_of_properties is 5, then the property at index 0, will take the value, of the property at index 0 - (-1) % 5 = 1 .

If rotation actually happens, so if the value of each property changes, then a PropertyNotify event, is generated for the window, for each of the rotated properties, in the order, they appear in the array.

Errors that can be generated by this function, are BadWindow, if the server, does not know about the window, BadAtom if the server, does not know about the atom, BadMatch , if the property is specified more than once, in the array, or if it does not belong to the window. If an error occurs, properties, are not rotated.

Example

In this example , three properties were created, and using XRotateWindowProperties, their values have been rotated.

  1. #include <X11/Xlib.h>

  2. #include <stdbool.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>

  5. int
  6.         main
  7.             (int argc , char* argv[ ] ){

  8.     // get a connection to the server
  9.     char* connection_string = NULL;
  10.     Display* display;
  11.     display =  XOpenDisplay (connection_string  );
  12.     if (display == NULL ){
  13.         fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" :  connection_string );
  14.         exit (EXIT_FAILURE );}


  15.     Atom atom_prop_1 = XInternAtom (display, "prop_1", false );
  16.     Atom atom_prop_2 = XInternAtom (display, "prop_2", false );
  17.     Atom atom_prop_3 = XInternAtom (display, "prop_3", false );

  18.     int number_properties = 3;
  19.     Atom properties[ ] = {atom_prop_1, atom_prop_2, atom_prop_3 };

  20.     Atom atom_type_int = XInternAtom (display, "type_int", false );

  21.     //Store some properties, on the root window
  22.     for  (long i = 0; i < number_properties; i++ )
  23.         XChangeProperty (display, //The connection
  24.             DefaultRootWindow (display ), //The window
  25.             properties[i ], //atom, Property name
  26.             atom_type_int, //atom, Property type
  27.             32, //Property format
  28.             PropModeReplace, //Property mode
  29.             (unsigned char *) &i, //Property data
  30.             1 ); //Number of data units

  31.     XRotateWindowProperties
  32.         (display,
  33.          DefaultRootWindow (display ),
  34.          properties,
  35.          number_properties,
  36.          1 ); //rotate properties by 1

  37.     /* Extract the rotated property values */
  38.     Atom returned_property_type;
  39.     int returned_property_format;
  40.     unsigned long returned_number_data_units;
  41.     unsigned long number_of_bytes_remaining_after_return;
  42.     long* retrieved_data;

  43.     printf("%-18s%-18s%-18s\n", "Property", "Old Value" , "New Value" );
  44.     for  (long i = 0; i < number_properties; i++ ){
  45.         XGetWindowProperty (display, //The connection
  46.                             DefaultRootWindow (display ), //The window
  47.                             properties[i ], //The property name
  48.                             0, //offset in 32 bits
  49.                             1, //number of elements in 32 bits
  50.                             False, //delete
  51.                             atom_type_int, //requested_property_type
  52.                             &returned_property_type,  //returned_property_type
  53.                             &returned_property_format, //returned_property_format
  54.                             &returned_number_data_units, //returned_number_data_units
  55.                             &number_of_bytes_remaining_after_return, //number_of_bytes_remaining_after_return
  56.                             (unsigned char** ) &retrieved_data /*retrieved_data */ );
  57.         printf("atom_prop_%-8ld  %-18d %-18d\n", i, i, *retrieved_data );}
  58.     /* Output
  59.         Property          Old Value         New Value
  60.         atom_prop_0         0                  2
  61.         atom_prop_1         1                  0
  62.         atom_prop_2         2                  1 */

  63.     XRotateWindowProperties
  64.         (display,
  65.          DefaultRootWindow (display ),
  66.          properties,
  67.          number_properties,
  68.          -1 ); //Reset the previous rotation


  69.     XRotateWindowProperties
  70.         (display,
  71.          DefaultRootWindow (display ),
  72.          properties,
  73.          number_properties,
  74.          2 ); //Rotate by 2

  75.     printf("\n\n%-18s%-18s%-18s\n", "Property", "Old Value" , "New Value" );
  76.     for  (long i = 0; i < number_properties; i++ ){
  77.         XGetWindowProperty (display, //The connection
  78.                             DefaultRootWindow (display ), //The window
  79.                             properties[i ], //The property name
  80.                             0, //offset in 32 bits
  81.                             1, //number of elements in 32 bits
  82.                             False, //delete
  83.                             atom_type_int, //requested_property_type
  84.                             &returned_property_type,  //returned_property_type
  85.                             &returned_property_format, //returned_property_format
  86.                             &returned_number_data_units, //returned_number_data_units
  87.                             &number_of_bytes_remaining_after_return, //number_of_bytes_remaining_after_return
  88.                             (unsigned char** ) &retrieved_data /*retrieved_data */ );
  89.         printf("atom_prop_%-8ld  %-18d %-18d\n", i, i, *retrieved_data );}
  90.     /* Output:
  91.         Property          Old Value         New Value
  92.         atom_prop_0         0                  1
  93.         atom_prop_1         1                  2
  94.         atom_prop_2         2                  0*/


  95.     for  (long i = 0; i < number_properties; i++ )
  96.         XDeleteProperty(
  97.         display,
  98.         DefaultRootWindow (display ),
  99.         properties[i ] );


  100.     XCloseDisplay(display);
  101.     return 0;}

The PropertyNotify event

what is the PropertyNotify event?

An event has a mask, used to register for the event, it has a type, used to query the type of the received event, and it has a structure, containing information, about the received event, of the given type.

PropertyNotify is the type of the event, which is generated for a window, when one of its properties, is modified.

In other words, this might happen, when a call to XChangeProperty is made, and is successful , or when a property has been deleted, by either a call to XGetWindowProperty , or XDeleteProperty .

The PropertyNotify event, also happens, once for each rotated property, when a call to XRotateWindowProperties, causes the properties values, to be rotated.

This being said, the PropertyChangeMask, is set on a window, in such a case, the server will notify the client, when this window’s properties, have been changed.

The PropertyChangeMask can be set on a window, using various functions, such as XSelectInput, XChangeWindowAttributes, or XCreateWindow.

Multiple clients, can register for the PropertyNotify event, of a given window, and once a property on this window, is changed, they will all be notified by the server.

The structure associated with the PropertyNotify event, is the XPropertyEvent structure.

Example

To illustrate, what has been said till now, let us give a concrete example:

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

  3. #include <stdbool.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>

  7. int
  8.         main
  9.             (int argc , char* argv[ ] ){

  10.     // get a connection to the server
  11.     char* connection_string = NULL;
  12.     Display* display;
  13.     display =  XOpenDisplay (connection_string  );
  14.     if (display == NULL ){
  15.         fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" :  connection_string );
  16.         exit (EXIT_FAILURE );}


  17.     // create a top level window
  18.     Window top_level_window;
  19.     top_level_window = XCreateSimpleWindow (
  20.         display ,
  21.         XDefaultRootWindow (display ), //parent window
  22.             // set the parent of top_level_window to the root window
  23.         0, //x position
  24.         0, //y position
  25.         300, //width
  26.         300, //height
  27.         0, //border width
  28.         0xFFFFFFFF , //border color
  29.         0xFF112233 /*background color .*/ );


  30.     XSelectInput (display, top_level_window, ExposureMask|PropertyChangeMask );
  31.     /* Using XSelectInput, register to receive
  32.         notifications, about the Expose and
  33.         PropertyNotify events, using the
  34.         event masks ExposureMask and
  35.         PropertyChangeMask .*/

  36.     XMapWindow (display, top_level_window );
  37.     /* Map the window to be exposed
  38.         later on .*/

  39.     XEvent xevent;
  40.     while (true ){ //handle events
  41.         XNextEvent (display, &xevent );
  42.         switch (xevent .type ){
  43.             case Expose:
  44.                 /*When the window is shown,
  45.                     change its title .*/
  46.                 XChangeProperty (display, //The connection
  47.                     top_level_window, //The window
  48.                     XA_WM_NAME, //atom, Property name, set the title
  49.                     XA_STRING, //atom, Property type
  50.                     8, //Property format
  51.                     PropModeAppend, //Property mode
  52.                     (unsigned char *) "Hey world", //Property data
  53.                     strlen ("Hey world") ); //Number of data units
  54.                 break;
  55.             case PropertyNotify:
  56.                 /*Print the name of the
  57.                     property, which is being
  58.                     modified .*/
  59.                 printf ("Property modified is : %s\n", XGetAtomName (display, xevent .xproperty .atom));
  60.                 break;
  61.         default:
  62.             break; }}

  63.     XCloseDisplay(display);
  64.     return 0;}
  65. /* Output:
  66. Property modified is : WM_NAME
  67. Property modified is : _WINDOWSWM_NATIVE_HWND
  68. Property modified is : WM_STATE */

The XSelectInput function

There are multiple functions, that can be used to inform an X11 server, that you are interested in it, reporting events, happening on a window, and they are the XSelectInput, XChangeWindowAttributes, and XCreateWindow functions.

The signature of the XSelectInput function is:

  1. XSelectInput
  2.     (Display* display,
  3.      Window window,
  4.      long event_mask)

display, is a reference, to a connection to the server, window, is the id of a window, which you are interested in one or more of its events, event_mask, is one or more events, related to the specified window, which you are interested in.

So from the previous example, the function was used as such:

  1. XSelectInput
  2.     (display,
  3.      top_level_window,
  4.      ExposureMask|PropertyChangeMask );
  5. /*Using XSelectInput, register to receive
  6.   notifications, about the Expose and
  7.   PropertyNotify events, using the
  8.   event masks ExposureMask and
  9.   PropertyChangeMask .*/

The XPropertyEvent structure

As it can be seen from the example,

  1. XEvent xevent;
  2. while (true ){ //handle events
  3.     XNextEvent (display, &xevent );
  4.     switch (xevent .type ){
  5.         case Expose:
  6.             ..
  7.             break;
  8.         case PropertyNotify:
  9.             .. XGetAtomName (display, xevent .xproperty .atom);

To retrieve events, you must use the XNextEvent function, and you pass in a reference, to a structure of type XEvent. This will set the value, for the variable xevent, which is of type XEvent.

At this stage, you can query for the type of event, using xevent .type, and if it is of type PropertyNotify, then you can access a structure of type XPropertyEvent , from xevent .

In this example, this was used to get the name of the property, that has changed, by accessing the atom field, of the xproperty structure.

This being said, the signature of the xproperty structure is:

  1. typedef struct {
  2.     int type;
  3.     unsigned long serial;
  4.     Bool send_event;
  5.     Display* display;
  6.     Window window;
  7.     Atom atom;
  8.     Time time;
  9.     int state;} XPropertyEvent;
  • type: is the type of the event, so in this case, it will be set to the value PropertyNotify.
  • serial: is of type unsigned long. Each request, is given a serial by the server, so serial, is just a number generated by the server.
  • send_event: is of type bool, it is set to true, if the event was sent by an application, using the XSendEvent function, or else it is set to false.
  • display: is of type Display*, so this is a reference to the connection, from which the event came.
  • window: is of type Window, so this is the id of the window, which generated this event. So in this case, a property has been changed.
  • atom: is of type Atom, so this is the atom identifying, the property name, on which there was a change.
  • time: is of type Time, which is defined as, typedef unsigned long Time;, in the <X11/X.h> header. It is the server time, as in a timestamp, when the property has been changed.
  • state: is of type int. It can take, one of the two values, PropertyNewValue or PropertyDeleted, and which are defined in the <X11/X.h> header.

    PropertyNewValue, is set, when a call to XChangeProperty is successful , or when a call to XRotateWindowProperties, results in the properties values, being rotated.

    PropertyDeleted, is set, when a call to XDeleteProperty, or XGetWindowProperty, results in the deletion of a property, associated with a window.