/*
Copyright (c) 2002 XFree86 Inc
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <X11/Xlibint.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xext.h>
#include <X11/extensions/extutil.h>
#include <X11/extensions/XResproto.h>
#include <X11/extensions/XRes.h>
#include <assert.h>
#include <limits.h>
static XExtensionInfo _xres_ext_info_data;
static XExtensionInfo *xres_ext_info = &_xres_ext_info_data;
static const char *xres_extension_name = XRES_NAME;
#define XResCheckExtension(dpy,i,val) \
XextCheckExtension (dpy, i, xres_extension_name, val)
static XEXT_GENERATE_CLOSE_DISPLAY (close_display, xres_ext_info)
static XExtensionHooks xres_extension_hooks = {
NULL, /* create_gc */
NULL, /* copy_gc */
NULL, /* flush_gc */
NULL, /* free_gc */
NULL, /* create_font */
NULL, /* free_font */
close_display, /* close_display */
NULL, /* wire_to_event */
NULL, /* event_to_wire */
NULL, /* error */
NULL, /* error_string */
};
static XEXT_GENERATE_FIND_DISPLAY (find_display, xres_ext_info,
xres_extension_name,
&xres_extension_hooks,
0, NULL)
Bool XResQueryExtension (
Display *dpy,
int *event_base_return,
int *error_base_return
)
{
XExtDisplayInfo *info = find_display (dpy);
if (XextHasExtension(info)) {
*event_base_return = info->codes->first_event;
*error_base_return = info->codes->first_error;
return True;
} else {
return False;
}
}
Status XResQueryVersion(
Display *dpy,
int *major_version_return,
int *minor_version_return
)
{
XExtDisplayInfo *info = find_display (dpy);
xXResQueryVersionReply rep;
xXResQueryVersionReq *req;
XResCheckExtension (dpy, info, 0);
LockDisplay (dpy);
GetReq (XResQueryVersion, req);
req->reqType = info->codes->major_opcode;
req->XResReqType = X_XResQueryVersion;
req->client_major = XRES_MAJOR_VERSION;
req->client_minor = XRES_MINOR_VERSION;
if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
UnlockDisplay (dpy);
SyncHandle ();
return 0;
}
*major_version_return = rep.server_major;
*minor_version_return = rep.server_minor;
UnlockDisplay (dpy);
SyncHandle ();
return 1;
}
Status XResQueryClients (
Display *dpy,
int *num_clients,
XResClient **clients
)
{
XExtDisplayInfo *info = find_display (dpy);
xXResQueryClientsReq *req;
xXResQueryClientsReply rep;
XResClient *clnts;
int result = 0;
*num_clients = 0;
*clients = NULL;
XResCheckExtension (dpy, info, 0);
LockDisplay (dpy);
GetReq (XResQueryClients, req);
req->reqType = info->codes->major_opcode;
req->XResReqType = X_XResQueryClients;
if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
UnlockDisplay (dpy);
SyncHandle ();
return 0;
}
if(rep.num_clients) {
if (rep.num_clients < (INT_MAX / sizeof(XResClient)))
clnts = Xmalloc(sizeof(XResClient) * rep.num_clients);
else
clnts = NULL;
if (clnts != NULL) {
xXResClient scratch;
int i;
for(i = 0; i < rep.num_clients; i++) {
_XRead(dpy, (char*)&scratch, sz_xXResClient);
clnts[i].resource_base = scratch.resource_base;
clnts[i].resource_mask = scratch.resource_mask;
}
*clients = clnts;
*num_clients = rep.num_clients;
result = 1;
} else {
_XEatDataWords(dpy, rep.length);
}
}
UnlockDisplay (dpy);
SyncHandle ();
return result;
}
Status XResQueryClientResources (
Display *dpy,
XID xid,
int *num_types,
XResType **types
)
{
XExtDisplayInfo *info = find_display (dpy);
xXResQueryClientResourcesReq *req;
xXResQueryClientResourcesReply rep;
XResType *typs;
int result = 0;
*num_types = 0;
*types = NULL;
XResCheckExtension (dpy, info, 0);
LockDisplay (dpy);
GetReq (XResQueryClientResources, req);
req->reqType = info->codes->major_opcode;
req->XResReqType = X_XResQueryClientResources;
req->xid = xid;
if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
UnlockDisplay (dpy);
SyncHandle ();
return 0;
}
if(rep.num_types) {
if (rep.num_types < (INT_MAX / sizeof(XResType)))
typs = Xmalloc(sizeof(XResType) * rep.num_types);
else
typs = NULL;
if (typs != NULL) {
xXResType scratch;
int i;
for(i = 0; i < rep.num_types; i++) {
_XRead(dpy, (char*)&scratch, sz_xXResType);
typs[i].resource_type = scratch.resource_type;
typs[i].count = scratch.count;
}
*types = typs;
*num_types = rep.num_types;
result = 1;
} else {
_XEatDataWords(dpy, rep.length);
}
}
UnlockDisplay (dpy);
SyncHandle ();
return result;
}
Status XResQueryClientPixmapBytes (
Display *dpy,
XID xid,
unsigned long *bytes
)
{
XExtDisplayInfo *info = find_display (dpy);
xXResQueryClientPixmapBytesReq *req;
xXResQueryClientPixmapBytesReply rep;
*bytes = 0;
XResCheckExtension (dpy, info, 0);
LockDisplay (dpy);
GetReq (XResQueryClientPixmapBytes, req);
req->reqType = info->codes->major_opcode;
req->XResReqType = X_XResQueryClientPixmapBytes;
req->xid = xid;
if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
UnlockDisplay (dpy);
SyncHandle ();
return 0;
}
#ifdef LONG64
*bytes = (rep.bytes_overflow * 4294967296UL) + rep.bytes;
#else
*bytes = rep.bytes_overflow ? 0xffffffff : rep.bytes;
#endif
UnlockDisplay (dpy);
SyncHandle ();
return 1;
}
static Bool ReadClientValues(
Display *dpy,
long num_ids,
XResClientIdValue *client_ids /* out */
)
{
int c;
for (c = 0; c < num_ids; ++c) {
XResClientIdValue* client = client_ids + c;
long int value;
_XRead32 (dpy, &value, 4);
client->spec.client = value;
_XRead32 (dpy, &value, 4);
client->spec.mask = value;
_XRead32 (dpy, &value, 4);
client->length = value;
client->value = malloc(client->length);
_XRead (dpy, client->value, client->length);
}
return True;
}
/* Returns an array of uint32_t values, not an array of long */
Status XResQueryClientIds (
Display *dpy,
long num_specs,
XResClientIdSpec *client_specs, /* in */
long *num_ids, /* out */
XResClientIdValue **client_ids /* out */
)
{
XExtDisplayInfo *info = find_display (dpy);
xXResQueryClientIdsReq *req;
xXResQueryClientIdsReply rep;
int c;
*num_ids = 0;
XResCheckExtension (dpy, info, 0);
LockDisplay (dpy);
GetReq (XResQueryClientIds, req);
req->reqType = info->codes->major_opcode;
req->XResReqType = X_XResQueryClientIds;
req->length += num_specs * 2; /* 2 longs per client id spec */
req->numSpecs = num_specs;
for (c = 0; c < num_specs; ++c) {
Data32(dpy, &client_specs[c].client, 4);
Data32(dpy, &client_specs[c].mask, 4);
}
if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
goto error;
}
*client_ids = calloc(rep.numIds, sizeof(**client_ids));
*num_ids = rep.numIds;
if (!ReadClientValues(dpy, *num_ids, *client_ids)) {
goto error;
}
UnlockDisplay (dpy);
SyncHandle ();
return Success;
error:
XResClientIdsDestroy (*num_ids, *client_ids);
*client_ids = NULL;
UnlockDisplay (dpy);
SyncHandle ();
return !Success;
}
void XResClientIdsDestroy (
long num_ids,
XResClientIdValue *client_ids
)
{
int c;
for (c = 0; c < num_ids; ++c) {
free(client_ids[c].value);
}
free(client_ids);
}
XResClientIdType XResGetClientIdType(
XResClientIdValue* value
)
{
int bit;
XResClientIdType idType = 0;
Bool found = False;
for (bit = 0; bit < XRES_CLIENT_ID_NR; ++bit) {
if (value->spec.mask & (1 << bit)) {
assert(!found);
found = True;
idType = bit;
}
}
assert(found);
return idType;
}
pid_t XResGetClientPid(
XResClientIdValue* value
)
{
if (value->spec.mask & XRES_CLIENT_ID_PID_MASK && value->length >= 4) {
return (pid_t) * (CARD32*) value->value;
} else {
return (pid_t) -1;
}
}
static Status ReadResourceSizeSpec(
Display *dpy,
XResResourceSizeSpec *size
)
{
long int value;
_XRead32(dpy, &value, 4);
size->spec.resource = value;
_XRead32(dpy, &value, 4);
size->spec.type = value;
_XRead32(dpy, &value, 4);
size->bytes = value;
_XRead32(dpy, &value, 4);
size->ref_count = value;
_XRead32(dpy, &value, 4);
size->use_count = value;
return 0;
}
static Status ReadResourceSizeValues(
Display *dpy,
long num_sizes,
XResResourceSizeValue *sizes)
{
int c;
int d;
for (c = 0; c < num_sizes; ++c) {
long int num;
ReadResourceSizeSpec(dpy, &sizes[c].size);
_XRead32(dpy, &num, 4);
sizes[c].num_cross_references = num;
sizes[c].cross_references = num ? calloc(num, sizeof(*sizes[c].cross_references)) : NULL;
for (d = 0; d < num; ++d) {
ReadResourceSizeSpec(dpy, &sizes[c].cross_references[d]);
}
}
return Success;
}
Status XResQueryResourceBytes (
Display *dpy,
XID client,
long num_specs,
XResResourceIdSpec *resource_specs, /* in */
long *num_sizes, /* out */
XResResourceSizeValue **sizes /* out */
)
{
XExtDisplayInfo *info = find_display (dpy);
xXResQueryResourceBytesReq *req;
xXResQueryResourceBytesReply rep;
int c;
*num_sizes = 0;
XResCheckExtension (dpy, info, 0);
LockDisplay (dpy);
GetReq (XResQueryResourceBytes, req);
req->reqType = info->codes->major_opcode;
req->XResReqType = X_XResQueryResourceBytes;
req->length += num_specs * 2; /* 2 longs per client id spec */
req->client = client;
req->numSpecs = num_specs;
for (c = 0; c < num_specs; ++c) {
Data32(dpy, &resource_specs[c].resource, 4);
Data32(dpy, &resource_specs[c].type, 4);
}
*num_sizes = 0;
*sizes = NULL;
if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
goto error;
}
*sizes = calloc(rep.numSizes, sizeof(**sizes));
*num_sizes = rep.numSizes;
if (ReadResourceSizeValues(dpy, *num_sizes, *sizes) != Success) {
goto error;
}
UnlockDisplay (dpy);
SyncHandle ();
return Success;
error:
XResResourceSizeValuesDestroy(*num_sizes, *sizes);
UnlockDisplay (dpy);
SyncHandle ();
return !Success;
}
void XResResourceSizeValuesDestroy (
long num_sizes,
XResResourceSizeValue *sizes
)
{
int c;
for (c = 0; c < num_sizes; ++c) {
free(sizes[c].cross_references);
}
free(sizes);
}