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.
Table of Contents
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:
XChangeProperty
(Display* display,
Window window,
Atom property_name,
Atom property_type,
int format,
int operation_mode,
unsigned char* property_data,
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:
typedef struct {
long flags;
Bool input;
int initial_state;
Pixmap icon_pixmap;
Window icon_window;
int icon_x;
int icon_y;
Pixmap icon_mask;
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 :
typedef struct {
short x, y;
} 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.
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main
(int argc , char* argv[ ] ){
// get a connection to the server
char* connection_string = NULL;
Display* display;
display = XOpenDisplay (connection_string );
if (display == NULL ){
fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" : connection_string );
exit (EXIT_FAILURE );}
// create a top level window
Window top_level_window;
top_level_window = XCreateSimpleWindow (
display ,
XDefaultRootWindow (display ), //parent window
// set the parent of top_level_window to the root window
0, //x position
0, //y position
300, //width
300, //height
0, //border width
0xFFFFFFFF , //border color
0xFF112233 /*background color .*/ );
XChangeProperty (display, //The connection
top_level_window, //The window
XA_WM_NAME, //atom, Property name
XA_STRING, //atom, Property type
8, //Property format
PropModeAppend, //Property mode
(unsigned char *) "Hey world", //Property data
strlen ("Hey world") ); //Number of data units
XSelectInput (display, top_level_window, ExposureMask );
//select the event, we want to handle
//In this case, the window being exposed
XMapWindow (display, top_level_window );
//Register a window to be
//exposed later on.
XEvent xevent;
while (true ){ //handle events
XNextEvent (display, &xevent );
switch (xevent .type ){
case Expose:
default:
break; }}
XCloseDisplay(display);
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:
int XGetWindowProperty
(Display* display,
Window window,
Atom property_name,
long data_offset_32,
long data_length_32,
Bool delete,
Atom requested_property_type,
Atom* returned_property_type,
int* returned_property_format,
unsigned long* returned_number_data_units,
unsigned long* number_of_bytes_remaining_after_return,
unsigned char** retrieved_data );
Display, is a reference to a connection to the server.windowis 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 thedeleteargument is ignored, the*returned_property_type, is set to the valueNone, which is defined as#define None 0L, in the<X11/Xatom.h>header,*returned_property_formatis set to0, and*number_of_bytes_remaining_after_return, is also set to0.So in other words, the request for information, for this property, has failed, hence its important, to set a property name, correctly.
-
data_offset_32is an offset, which is a multiple of32, as in32bits. For example, it can be0, so the offset is0, it can be1, so the offset is32, it can be2, so the offset is64…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
BadValueerror. data_length_32, is the number of32bits, 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, aBadValueerror.deleteif true, means that this property, is going to be deleted, if and only ifnumber_of_bytes_remaining_after_returnis0.If the property is deleted, then a
PropertyNotifyevent, is generated, for the window, associated with this property.property_type_requestedis 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
deleteargument is ignored, thereturned_property_type, will be a reference to the actual property type, thereturned_property_formatwill be a reference to the actual property format, andnumber_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_formatis set to the actual property format,*returned_number_data_unitsis set to the number of units, as defined in property format, as in8or16or32, 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_datais 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, or32bit.number_units_data_returned, is a reference, to the number of8or16or32bits, 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 typeunsigned char**, so this means, that you provide the address, of anunsigned 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
8bits, then the memory pointed, by your pointer, will be of typechar, if the property data format is16bits, then your pointer, is pointing to a memory of typeshort, and if it is32bits, 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 .
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main
(int argc , char* argv[ ] ){
// get a connection to the server
char* connection_string = NULL;
Display* display;
display = XOpenDisplay (connection_string );
if (display == NULL ){
fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" : connection_string );
exit (EXIT_FAILURE );}
// create a top level window
Window top_level_window;
top_level_window = XCreateSimpleWindow (
display ,
XDefaultRootWindow (display ), //parent window
// set the parent of top_level_window to the root window
0, //x position
0, //y position
300, //width
300, //height
0, //border width
0xFFFFFFFF , //border color
0xFF112233 /*background color .*/ );
/*Declare the values, to be returned
by a call to the XGetWindowProperty
function. */
Atom returned_property_type;
int returned_property_format;
unsigned long returned_number_data_units;
unsigned long number_of_bytes_remaining_after_return;
long* retrieved_data;
//Getting a property with an invalid name
int status = XGetWindowProperty (display, //The connection
top_level_window, //The window
XA_WM_NAME, //The property name
0, //offset in 32 bits
1, //number of elements in 32 bits
False, //delete
XA_INTEGER, //requested_property_type
&returned_property_type, //returned_property_type
&returned_property_format, //returned_property_format
&returned_number_data_units, //returned_number_data_units
&number_of_bytes_remaining_after_return, //number_of_bytes_remaining_after_return
(unsigned char** ) &retrieved_data /*retrieved_data */ );
printf("Results of getting a property, with an invalid name: \n" );
printf("\tstatus is : %d\n", status );
/*If returned_property_type is None,
and both of returned_property_format
and returned_number_data_units are
0, then the property name is
invalid.*/
printf("\treturned_property_type is : %lu\n", returned_property_type );
printf("\treturned_property_format is : %d\n", returned_property_format );
printf("\treturned_number_data_units is : %lu\n\n\n", returned_number_data_units );
/* Output:
Results of getting a property, with an invalid name:
status is : 0
returned_property_type is : 0
returned_property_format is : 0
returned_number_data_units is : 0 */
//Create an atom for a string
//which will be used, as our
//own property name.
Atom my_prop_atom = XInternAtom (display, "MY_PROPERTY", false );
int my_prop_data_len = 5;
long my_prop_data [ ] = {4294967297, 5, 6, 8, 10 };
//Define a property, on the
//top level window.
XChangeProperty (display, //The connection
top_level_window, //The window
my_prop_atom, //atom, Property name
XA_INTEGER, //atom, Property type
32, //Property format
PropModeAppend, //Property mode
(unsigned char *) my_prop_data, //Property data
my_prop_data_len ); //Number of data units
printf("Results of getting a property, with a valid name: \n" );
long offset = 0;
long length = 1;
do{
status = XGetWindowProperty (display, //The connection
top_level_window, //The window
my_prop_atom, //The property name
offset, //offset in 32 bits
length, //number of elements in 32 bits
False, //delete
XA_INTEGER, //requested_property_type
&returned_property_type, //returned_property_type
&returned_property_format, //returned_property_format
&returned_number_data_units, //returned_number_data_units
&number_of_bytes_remaining_after_return, //number_of_bytes_remaining_after_return
(unsigned char** ) &retrieved_data /*retrieved_data */ );
printf("\tstatus is : %d\n", status );
printf("\treturned_property_type is : %lu\n", returned_property_type );
printf("\treturned_property_format is : %d\n", returned_property_format );
printf("\treturned_number_data_units is : %lu\n", returned_number_data_units );
printf("\tnumber_of_bytes_remaining_after_return is : %lu\n", number_of_bytes_remaining_after_return );
printf("\tretrieved property data is: %ld\n\n", *retrieved_data );
offset++;
XFree (retrieved_data );
}while (number_of_bytes_remaining_after_return != 0 );
/* Output:
Results of getting a property, with a valid name:
status is : 0
returned_property_type is : 19
returned_property_format is : 32
returned_number_data_units is : 1
number_of_bytes_remaining_after_return is : 16
retrieved property data is: 1
status is : 0
returned_property_type is : 19
returned_property_format is : 32
returned_number_data_units is : 1
number_of_bytes_remaining_after_return is : 12
retrieved property data is: 5
status is : 0
returned_property_type is : 19
returned_property_format is : 32
returned_number_data_units is : 1
number_of_bytes_remaining_after_return is : 8
retrieved property data is: 6
status is : 0
returned_property_type is : 19
returned_property_format is : 32
returned_number_data_units is : 1
number_of_bytes_remaining_after_return is : 4
retrieved property data is: 8
status is : 0
returned_property_type is : 19
returned_property_format is : 32
returned_number_data_units is : 1
number_of_bytes_remaining_after_return is : 0
retrieved property data is: 10 */
XSelectInput (display, top_level_window, ExposureMask );
//select the event, we want to handle
//In this case, the window being exposed
XMapWindow (display, top_level_window );
//Register a window to be
//exposed later on.
XEvent xevent;
while (true ){ //handle events
XNextEvent (display, &xevent );
switch (xevent .type ){
case Expose:
default:
break; }}
XCloseDisplay(display);
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:
Atom* XListProperties
(Display* display,
Window window,
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.
$ xclock &
# Launch the xclock
# program.
$ xprop
# after clicking on xclock
# the following is displayed
WM_STATE(WM_STATE):
window state: Normal
icon window: 0x0
_NET_WM_PID(CARDINAL) = 5208
_WINDOWSWM_NATIVE_HWND(INTEGER) = 2689576, 0
WM_PROTOCOLS(ATOM): protocols WM_DELETE_WINDOW
WM_CLIENT_LEADER(WINDOW): window id # 0x80000a
WM_LOCALE_NAME(STRING) = "en_US.UTF-8"
WM_CLASS(STRING) = "xclock", "XClock"
WM_HINTS(WM_HINTS):
Client accepts input or input focus: False
Initial state is Normal State.
bitmap id # to use for icon: 0x800001
bitmap id # of mask for icon: 0x800003
WM_NORMAL_HINTS(WM_SIZE_HINTS):
program specified size: 164 by 164
window gravity: NorthWest
WM_CLIENT_MACHINE(STRING) = "DSKTP-TOAPK1I"
WM_COMMAND(STRING) = { "xclock" }
WM_ICON_NAME(STRING) = "xclock"
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.
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
int
main
(int argc , char* argv[ ] ){
// get a connection to the server
char* connection_string = NULL;
Display* display;
display = XOpenDisplay (connection_string );
if (display == NULL ){
fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" : connection_string );
exit (EXIT_FAILURE );}
//List the properties of the root window
Atom* root_window_properties;
int number_returned_properties;
root_window_properties = XListProperties (display, //The display
DefaultRootWindow (display), //The root window
&number_returned_properties ); //The number of returned properties.
if (root_window_properties != NULL ){
printf ("atom\tname\n");
for (int i = 0; i < number_returned_properties; i++ ){
printf("%4lu\t%4s\t\n", root_window_properties [i ], XGetAtomName (display, root_window_properties[i ] ));}}
XCloseDisplay(display);
return 0;}
/* Output:
atom name
241 __NET_DESKTOP_NAMES
240 _NET_NUMBER_OF_DESKTOPS
239 _NET_CURRENT_DESKTOP
243 _NET_SUPPORTED
38 WM_ICON_SIZE
232 _XKB_RULES_NAMES
*/
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 :
XDeleteProperty
(Display* display,
Window window,
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.
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main
(int argc , char* argv[ ] ){
// get a connection to the server
char* connection_string = NULL;
Display* display;
display = XOpenDisplay (connection_string );
if (display == NULL ){
fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" : connection_string );
exit (EXIT_FAILURE );}
Atom atom = XInternAtom (display, "a_property_name", false );
XChangeProperty (display, //The connection
DefaultRootWindow (display ), //The window
atom, //atom, Property name
XA_STRING, //atom, Property type
8, //Property format
PropModeReplace, //Property mode
(unsigned char *) "Property data", //Property data
strlen ("Property data" ) ); //Number of data units
XDeleteProperty(
display,
DefaultRootWindow(display),
atom );
XCloseDisplay(display);
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.
$ 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:
XRotateWindowProperties
(Display* display,
Window window,
Atom* properties,
int number_of_properties,
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.
#include <X11/Xlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
int
main
(int argc , char* argv[ ] ){
// get a connection to the server
char* connection_string = NULL;
Display* display;
display = XOpenDisplay (connection_string );
if (display == NULL ){
fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" : connection_string );
exit (EXIT_FAILURE );}
Atom atom_prop_1 = XInternAtom (display, "prop_1", false );
Atom atom_prop_2 = XInternAtom (display, "prop_2", false );
Atom atom_prop_3 = XInternAtom (display, "prop_3", false );
int number_properties = 3;
Atom properties[ ] = {atom_prop_1, atom_prop_2, atom_prop_3 };
Atom atom_type_int = XInternAtom (display, "type_int", false );
//Store some properties, on the root window
for (long i = 0; i < number_properties; i++ )
XChangeProperty (display, //The connection
DefaultRootWindow (display ), //The window
properties[i ], //atom, Property name
atom_type_int, //atom, Property type
32, //Property format
PropModeReplace, //Property mode
(unsigned char *) &i, //Property data
1 ); //Number of data units
XRotateWindowProperties
(display,
DefaultRootWindow (display ),
properties,
number_properties,
1 ); //rotate properties by 1
/* Extract the rotated property values */
Atom returned_property_type;
int returned_property_format;
unsigned long returned_number_data_units;
unsigned long number_of_bytes_remaining_after_return;
long* retrieved_data;
printf("%-18s%-18s%-18s\n", "Property", "Old Value" , "New Value" );
for (long i = 0; i < number_properties; i++ ){
XGetWindowProperty (display, //The connection
DefaultRootWindow (display ), //The window
properties[i ], //The property name
0, //offset in 32 bits
1, //number of elements in 32 bits
False, //delete
atom_type_int, //requested_property_type
&returned_property_type, //returned_property_type
&returned_property_format, //returned_property_format
&returned_number_data_units, //returned_number_data_units
&number_of_bytes_remaining_after_return, //number_of_bytes_remaining_after_return
(unsigned char** ) &retrieved_data /*retrieved_data */ );
printf("atom_prop_%-8ld %-18d %-18d\n", i, i, *retrieved_data );}
/* Output
Property Old Value New Value
atom_prop_0 0 2
atom_prop_1 1 0
atom_prop_2 2 1 */
XRotateWindowProperties
(display,
DefaultRootWindow (display ),
properties,
number_properties,
-1 ); //Reset the previous rotation
XRotateWindowProperties
(display,
DefaultRootWindow (display ),
properties,
number_properties,
2 ); //Rotate by 2
printf("\n\n%-18s%-18s%-18s\n", "Property", "Old Value" , "New Value" );
for (long i = 0; i < number_properties; i++ ){
XGetWindowProperty (display, //The connection
DefaultRootWindow (display ), //The window
properties[i ], //The property name
0, //offset in 32 bits
1, //number of elements in 32 bits
False, //delete
atom_type_int, //requested_property_type
&returned_property_type, //returned_property_type
&returned_property_format, //returned_property_format
&returned_number_data_units, //returned_number_data_units
&number_of_bytes_remaining_after_return, //number_of_bytes_remaining_after_return
(unsigned char** ) &retrieved_data /*retrieved_data */ );
printf("atom_prop_%-8ld %-18d %-18d\n", i, i, *retrieved_data );}
/* Output:
Property Old Value New Value
atom_prop_0 0 1
atom_prop_1 1 2
atom_prop_2 2 0*/
for (long i = 0; i < number_properties; i++ )
XDeleteProperty(
display,
DefaultRootWindow (display ),
properties[i ] );
XCloseDisplay(display);
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:
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main
(int argc , char* argv[ ] ){
// get a connection to the server
char* connection_string = NULL;
Display* display;
display = XOpenDisplay (connection_string );
if (display == NULL ){
fprintf (stderr, "Error: XOpenDisplay (%s )\n", connection_string == NULL ? "NULL" : connection_string );
exit (EXIT_FAILURE );}
// create a top level window
Window top_level_window;
top_level_window = XCreateSimpleWindow (
display ,
XDefaultRootWindow (display ), //parent window
// set the parent of top_level_window to the root window
0, //x position
0, //y position
300, //width
300, //height
0, //border width
0xFFFFFFFF , //border color
0xFF112233 /*background color .*/ );
XSelectInput (display, top_level_window, ExposureMask|PropertyChangeMask );
/* Using XSelectInput, register to receive
notifications, about the Expose and
PropertyNotify events, using the
event masks ExposureMask and
PropertyChangeMask .*/
XMapWindow (display, top_level_window );
/* Map the window to be exposed
later on .*/
XEvent xevent;
while (true ){ //handle events
XNextEvent (display, &xevent );
switch (xevent .type ){
case Expose:
/*When the window is shown,
change its title .*/
XChangeProperty (display, //The connection
top_level_window, //The window
XA_WM_NAME, //atom, Property name, set the title
XA_STRING, //atom, Property type
8, //Property format
PropModeAppend, //Property mode
(unsigned char *) "Hey world", //Property data
strlen ("Hey world") ); //Number of data units
break;
case PropertyNotify:
/*Print the name of the
property, which is being
modified .*/
printf ("Property modified is : %s\n", XGetAtomName (display, xevent .xproperty .atom));
break;
default:
break; }}
XCloseDisplay(display);
return 0;}
/* Output:
Property modified is : WM_NAME
Property modified is : _WINDOWSWM_NATIVE_HWND
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:
XSelectInput
(Display* display,
Window window,
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:
XSelectInput
(display,
top_level_window,
ExposureMask|PropertyChangeMask );
/*Using XSelectInput, register to receive
notifications, about the Expose and
PropertyNotify events, using the
event masks ExposureMask and
PropertyChangeMask .*/
The XPropertyEvent structure
As it can be seen from the example,
XEvent xevent;
while (true ){ //handle events
XNextEvent (display, &xevent );
switch (xevent .type ){
case Expose:
..
break;
case PropertyNotify:
.. 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:
typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display* display;
Window window;
Atom atom;
Time time;
int state;} XPropertyEvent;
-
type: is the type of the event, so in this case, it will be set to the valuePropertyNotify. -
serial: is of typeunsigned long. Each request, is given a serial by the server, so serial, is just a number generated by the server. -
send_event: is of typebool, it is set to true, if the event was sent by an application, using theXSendEventfunction, or else it is set to false. -
display: is of typeDisplay*, so this is a reference to the connection, from which the event came. -
window: is of typeWindow, so this is the id of the window, which generated this event. So in this case, a property has been changed. -
atom: is of typeAtom, so this is the atom identifying, the property name, on which there was a change. -
time: is of typeTime, 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 typeint. It can take, one of the two values,PropertyNewValueorPropertyDeleted, and which are defined in the<X11/X.h>header.PropertyNewValue, is set, when a call toXChangePropertyis successful , or when a call toXRotateWindowProperties, results in the properties values, being rotated.PropertyDeleted, is set, when a call toXDeleteProperty, orXGetWindowProperty, results in the deletion of a property, associated with a window.

