devPrivates are a way to store information in a struct without modifying the header for the struct, thus keeping the ABI.
Each major struct (ScreenRec, DeviceIntRec, WindowRec, ClientRec) has a pointer to it's devPrivates as part of the struct. The usage of the devPrivates is as follows:
#include <privates.h> DevPrivatesKey myKey = &myKey; void store_private(ClientPtr client) { MyStruct *a = xalloc(sizeof(MyStruct)); /* do stuff with a */ dixSetPrivate(&client->devPrivates, myKey, a); } void retrieve_private(ClientPtr client) { MyStruct *a; a = (MyStruct*)dixLookupPrivate(&client->devPrivates, myKey); /* do stuff with a */ } /* The following will free _ALL_ devPrivates on the given client. Not just yours! */ void delete_private(ClientPtr client) { dixFreePrivates(client->devPrivates); }
devPrivates are more fully documented in the Definition of the Porting Layer for the X v11 Sample Server document, sources of which are in xorg-docs/sgml/core/Xserver-spec.xml
Deprecated information
The following is a description of the devPrivates system before the serious overhaul. It is now outdated.
Client devPrivates are similar to those of the ScreenRec and DeviceIntRec structures, but those have their own API to initialize and access them. Please note that there a overhaul of the devPrivates system in progress and this information may be out of date soon - see http://lists.freedesktop.org/archives/xorg/2007-March/022212.html.
Need to be initialised at start time, as each time a client is allocated. The devPrivates are an array of DevUnions that are allocated when the client starts and released when the client finishes. Each client has the same size allocated for devPrivates and at the moment there are no methods to resize the array at a later point in time. Better make sure you allocate everything on server startup before the first client connects.
AllocateClientPrivatesIndex() gives you an index into the array. Each time you need to access your data, access it with client->devPrivates[MyIndex].ptr
and cast it to your specific data information. Immediately after retrieving your index, call AllocateClientPrivate(MyIndex, size), where size is the number of bytes you need for your private struct in bytes. You can now assume that every client that connects will have enough space for your data.
Finally, you will probably want to add a callback to reset the data when a client starts up. Use AddCallback() to register your function and then do stuff. The first argument is always the same (ClientStateCallback), the second your callback proc and the third one some pointer data which will get passed into the callback function (argument closure in example below). Most extensions just pass in 0. You need to check the state of the client in the callback function. If client->state is ClientStateRunning then the client has just started up, ClientStateGone or ClientStateRetained means it has been shut down. There are a few other states. (comment by Eamon Walsh)
I recommend looking at damageext/damageext.c, it has a low signal-to-noise ratio. The full code you need:
int myIndex = AllocateClientPrivateIndex(); /* check myIndex > 0 */ AllocateClientPrivate(myIndex, sizeof(MyStruct)); /* has to return true */ AddCallback(&ClientStateCallback, MyCallbackProc, 0); static void MyCallbackProc(CallbackListPtr *list, pointer closure, pointer data) { NewClientInfoRec* clientinfo = (NewClientInfoRec*)data; ClientPtr client = clientinfo->client; MyStruct mystruct = (MyStruct*)client->devPrivates[myIndex].ptr; /* do stuff */ }
Finally, you want to add a DeleteCallback() call to remove your callback when the extension resets.
Notes
The client that owns the root window is serverClient
and will be created before extensions initialize. It will (most likely) not have devPrivates set to what you added, so make sure you cater for this.
Window DevPrivates
The devPrivates of a WindowRec are stored after the struct's memory. Each screen keeps a totalWindowSize for the memory that is to be allocated per screen. The memory for a WindowRec with 4 devPrivates entries looks approximately like this:
___________________________________________________________________________ | | | | | | | | | | | WindowRec | 1 | 2 | 3 | 4 | A | B | C | D | |___________dP__|___|___|___|___|__________|_____________|___|______________| | ^ | | | | ^ ^ ^ ^ |__| | | | |__|__________|_____________|___| | | |______|__________|_____________| | |__________|__________| |______________|
With 1 = &A, 2 = &B,
etc. Before you allocate a window, you need to call AllocateWindowPrivate() with the size you need for your entry. A, B, C, D have the sizes that were specified for AllocateWindowPrivate