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.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 thedelete
argument 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_format
is 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_32
is an offset, which is a multiple of32
, as in32
bits. 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
BadValue
error. data_length_32
, is the number of32
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, aBadValue
error.delete
if true, means that this property, is going to be deleted, if and only ifnumber_of_bytes_remaining_after_return
is0
.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, thereturned_property_type
, will be a reference to the actual property type, thereturned_property_format
will 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_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 in8
or16
or32
, 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
, or32
bit.number_units_data_returned
, is a reference, to the number of8
or16
or32
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 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
8
bits, then the memory pointed, by your pointer, will be of typechar
, if the property data format is16
bits, then your pointer, is pointing to a memory of typeshort
, and if it is32
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 .
#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 theXSendEvent
function, 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,PropertyNewValue
orPropertyDeleted
, and which are defined in the<X11/X.h>
header.PropertyNewValue
, is set, when a call toXChangeProperty
is 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.