#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <X11/X.h>
#include <X11/Xproto.h>
#include "windowstr.h"
#include "propertyst.h"
#include "dixstruct.h"
#include "dispatch.h"
#include "swaprep.h"
#include "xace.h"
#ifdef notdef
static void
PrintPropertys(WindowPtr pWin)
{
PropertyPtr pProp;
int j;
pProp = pWin->userProps;
while (pProp)
{
ErrorF("[dix] %x %x\n", pProp->propertyName, pProp->type);
ErrorF("[dix] property format: %d\n", pProp->format);
ErrorF("[dix] property data: \n");
for (j=0; j<(pProp->format/8)*pProp->size; j++)
ErrorF("[dix] %c\n", pProp->data[j]);
pProp = pProp->next;
}
}
#endif
int
dixLookupProperty(PropertyPtr *result, WindowPtr pWin, Atom propertyName,
ClientPtr client, Mask access_mode)
{
PropertyPtr pProp;
int rc = BadMatch;
client->errorValue = propertyName;
for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
if (pProp->propertyName == propertyName)
break;
if (pProp)
rc = XaceHookPropertyAccess(client, pWin, &pProp, access_mode);
*result = pProp;
return rc;
}
static void
deliverPropertyNotifyEvent(WindowPtr pWin, int state, Atom atom)
{
xEvent event;
memset(&event, 0, sizeof(xEvent));
event.u.u.type = PropertyNotify;
event.u.property.window = pWin->drawable.id;
event.u.property.state = state;
event.u.property.atom = atom;
event.u.property.time = currentTime.milliseconds;
DeliverEvents(pWin, &event, 1, (WindowPtr)NULL);
}
int
ProcRotateProperties(ClientPtr client)
{
int i, j, delta, rc;
REQUEST(xRotatePropertiesReq);
WindowPtr pWin;
Atom * atoms;
PropertyPtr * props;
PropertyPtr pProp, saved;
REQUEST_FIXED_SIZE(xRotatePropertiesReq, stuff->nAtoms << 2);
UpdateCurrentTime();
rc = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
if (rc != Success || stuff->nAtoms <= 0)
return rc;
atoms = (Atom *) & stuff[1];
props = malloc(stuff->nAtoms * sizeof(PropertyPtr));
saved = malloc(stuff->nAtoms * sizeof(PropertyRec));
if (!props || !saved) {
rc = BadAlloc;
goto out;
}
for (i = 0; i < stuff->nAtoms; i++)
{
if (!ValidAtom(atoms[i])) {
rc = BadAtom;
client->errorValue = atoms[i];
goto out;
}
for (j = i + 1; j < stuff->nAtoms; j++)
if (atoms[j] == atoms[i])
{
rc = BadMatch;
goto out;
}
rc = dixLookupProperty(&pProp, pWin, atoms[i], client,
DixReadAccess|DixWriteAccess);
if (rc != Success)
goto out;
props[i] = pProp;
saved[i] = *pProp;
}
delta = stuff->nPositions;
if (abs(delta) % stuff->nAtoms)
{
while (delta < 0)
delta += stuff->nAtoms;
for (i = 0; i < stuff->nAtoms; i++)
{
j = (i + delta) % stuff->nAtoms;
deliverPropertyNotifyEvent(pWin, PropertyNewValue, atoms[i]);
props[j]->type = saved[i].type;
props[j]->format = saved[i].format;
props[j]->size = saved[i].size;
props[j]->data = saved[i].data;
}
}
out:
free(saved);
free(props);
return rc;
}
int
ProcChangeProperty(ClientPtr client)
{
WindowPtr pWin;
char format, mode;
unsigned long len;
int sizeInBytes, totalSize, err;
REQUEST(xChangePropertyReq);
REQUEST_AT_LEAST_SIZE(xChangePropertyReq);
UpdateCurrentTime();
format = stuff->format;
mode = stuff->mode;
if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
(mode != PropModePrepend))
{
client->errorValue = mode;
return BadValue;
}
if ((format != 8) && (format != 16) && (format != 32))
{
client->errorValue = format;
return BadValue;
}
len = stuff->nUnits;
if (len > bytes_to_int32(0xffffffff - sizeof(xChangePropertyReq)))
return BadLength;
sizeInBytes = format>>3;
totalSize = len * sizeInBytes;
REQUEST_FIXED_SIZE(xChangePropertyReq, totalSize);
err = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
if (err != Success)
return err;
if (!ValidAtom(stuff->property))
{
client->errorValue = stuff->property;
return BadAtom;
}
if (!ValidAtom(stuff->type))
{
client->errorValue = stuff->type;
return BadAtom;
}
err = dixChangeWindowProperty(client, pWin, stuff->property, stuff->type,
(int)format, (int)mode, len, &stuff[1],
TRUE);
if (err != Success)
return err;
else
return Success;
}
int
dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
Atom type, int format, int mode, unsigned long len,
pointer value, Bool sendevent)
{
PropertyPtr pProp;
PropertyRec savedProp;
int sizeInBytes, totalSize, rc;
unsigned char *data;
Mask access_mode;
sizeInBytes = format>>3;
totalSize = len * sizeInBytes;
access_mode = (mode == PropModeReplace) ? DixWriteAccess : DixBlendAccess;
rc = dixLookupProperty(&pProp, pWin, property, pClient, access_mode);
if (rc == BadMatch)
{
if (!pWin->optional && !MakeWindowOptional (pWin))
return BadAlloc;
pProp = dixAllocateObjectWithPrivates(PropertyRec, PRIVATE_PROPERTY);
if (!pProp)
return BadAlloc;
data = malloc(totalSize);
if (!data && len)
{
dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
return BadAlloc;
}
memcpy(data, value, totalSize);
pProp->propertyName = property;
pProp->type = type;
pProp->format = format;
pProp->data = data;
pProp->size = len;
rc = XaceHookPropertyAccess(pClient, pWin, &pProp,
DixCreateAccess|DixWriteAccess);
if (rc != Success) {
free(data);
dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
pClient->errorValue = property;
return rc;
}
pProp->next = pWin->optional->userProps;
pWin->optional->userProps = pProp;
}
else if (rc == Success)
{
if ((format != pProp->format) && (mode != PropModeReplace))
return BadMatch;
if ((pProp->type != type) && (mode != PropModeReplace))
return BadMatch;
savedProp = *pProp;
if (mode == PropModeReplace)
{
data = malloc(totalSize);
if (!data && len)
return BadAlloc;
memcpy(data, value, totalSize);
pProp->data = data;
pProp->size = len;
pProp->type = type;
pProp->format = format;
}
else if (len == 0)
{
}
else if (mode == PropModeAppend)
{
data = malloc((pProp->size + len) * sizeInBytes);
if (!data)
return BadAlloc;
memcpy(data, pProp->data, pProp->size * sizeInBytes);
memcpy(data + pProp->size * sizeInBytes, value, totalSize);
pProp->data = data;
pProp->size += len;
}
else if (mode == PropModePrepend)
{
data = malloc(sizeInBytes * (len + pProp->size));
if (!data)
return BadAlloc;
memcpy(data + totalSize, pProp->data, pProp->size * sizeInBytes);
memcpy(data, value, totalSize);
pProp->data = data;
pProp->size += len;
}
access_mode |= DixPostAccess;
rc = XaceHookPropertyAccess(pClient, pWin, &pProp, access_mode);
if (rc == Success)
{
if (savedProp.data != pProp->data)
free(savedProp.data);
}
else
{
if (savedProp.data != pProp->data)
free(pProp->data);
*pProp = savedProp;
return rc;
}
}
else
return rc;
if (sendevent)
deliverPropertyNotifyEvent(pWin, PropertyNewValue, pProp->propertyName);
return Success;
}
int
ChangeWindowProperty(WindowPtr pWin, Atom property, Atom type, int format,
int mode, unsigned long len, pointer value,
Bool sendevent)
{
return dixChangeWindowProperty(serverClient, pWin, property, type, format,
mode, len, value, sendevent);
}
int
DeleteProperty(ClientPtr client, WindowPtr pWin, Atom propName)
{
PropertyPtr pProp, prevProp;
int rc;
rc = dixLookupProperty(&pProp, pWin, propName, client, DixDestroyAccess);
if (rc == BadMatch)
return Success;
if (rc == Success) {
if (pWin->optional->userProps == pProp) {
if (!(pWin->optional->userProps = pProp->next))
CheckWindowOptionalNeed (pWin);
} else {
prevProp = pWin->optional->userProps;
while (prevProp->next != pProp)
prevProp = prevProp->next;
prevProp->next = pProp->next;
}
deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
free(pProp->data);
dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
}
return rc;
}
void
DeleteAllWindowProperties(WindowPtr pWin)
{
PropertyPtr pProp, pNextProp;
pProp = wUserProps (pWin);
while (pProp)
{
deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
pNextProp = pProp->next;
free(pProp->data);
dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
pProp = pNextProp;
}
if (pWin->optional)
pWin->optional->userProps = NULL;
}
static int
NullPropertyReply(
ClientPtr client,
ATOM propertyType,
int format,
xGetPropertyReply *reply)
{
reply->nItems = 0;
reply->length = 0;
reply->bytesAfter = 0;
reply->propertyType = propertyType;
reply->format = format;
WriteReplyToClient(client, sizeof(xGenericReply), reply);
return Success;
}
int
ProcGetProperty(ClientPtr client)
{
PropertyPtr pProp, prevProp;
unsigned long n, len, ind;
int rc;
WindowPtr pWin;
xGetPropertyReply reply;
Mask win_mode = DixGetPropAccess, prop_mode = DixReadAccess;
REQUEST(xGetPropertyReq);
REQUEST_SIZE_MATCH(xGetPropertyReq);
if (stuff->delete) {
UpdateCurrentTime();
win_mode |= DixSetPropAccess;
prop_mode |= DixDestroyAccess;
}
rc = dixLookupWindow(&pWin, stuff->window, client, win_mode);
if (rc != Success)
return (rc == BadMatch) ? BadWindow : rc;
if (!ValidAtom(stuff->property))
{
client->errorValue = stuff->property;
return BadAtom;
}
if ((stuff->delete != xTrue) && (stuff->delete != xFalse))
{
client->errorValue = stuff->delete;
return BadValue;
}
if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type))
{
client->errorValue = stuff->type;
return BadAtom;
}
memset(&reply, 0, sizeof(xGetPropertyReply));
reply.type = X_Reply;
reply.sequenceNumber = client->sequence;
rc = dixLookupProperty(&pProp, pWin, stuff->property, client, prop_mode);
if (rc == BadMatch)
return NullPropertyReply(client, None, 0, &reply);
else if (rc != Success)
return rc;
if (((stuff->type != pProp->type) &&
(stuff->type != AnyPropertyType))
)
{
reply.bytesAfter = pProp->size;
reply.format = pProp->format;
reply.length = 0;
reply.nItems = 0;
reply.propertyType = pProp->type;
WriteReplyToClient(client, sizeof(xGenericReply), &reply);
return Success;
}
n = (pProp->format/8) * pProp->size;
ind = stuff->longOffset << 2;
if (n < ind)
{
client->errorValue = stuff->longOffset;
return BadValue;
}
len = min(n - ind, 4 * stuff->longLength);
reply.bytesAfter = n - (ind + len);
reply.format = pProp->format;
reply.length = bytes_to_int32(len);
reply.nItems = len / (pProp->format / 8 );
reply.propertyType = pProp->type;
if (stuff->delete && (reply.bytesAfter == 0))
deliverPropertyNotifyEvent(pWin, PropertyDelete, pProp->propertyName);
WriteReplyToClient(client, sizeof(xGenericReply), &reply);
if (len)
{
switch (reply.format) {
case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
}
WriteSwappedDataToClient(client, len,
(char *)pProp->data + ind);
}
if (stuff->delete && (reply.bytesAfter == 0)) {
if (pWin->optional->userProps == pProp) {
if (!(pWin->optional->userProps = pProp->next))
CheckWindowOptionalNeed (pWin);
} else {
prevProp = pWin->optional->userProps;
while (prevProp->next != pProp)
prevProp = prevProp->next;
prevProp->next = pProp->next;
}
free(pProp->data);
dixFreeObjectWithPrivates(pProp, PRIVATE_PROPERTY);
}
return Success;
}
int
ProcListProperties(ClientPtr client)
{
Atom *pAtoms = NULL, *temppAtoms;
xListPropertiesReply xlpr;
int rc, numProps = 0;
WindowPtr pWin;
PropertyPtr pProp, realProp;
REQUEST(xResourceReq);
REQUEST_SIZE_MATCH(xResourceReq);
rc = dixLookupWindow(&pWin, stuff->id, client, DixListPropAccess);
if (rc != Success)
return rc;
for (pProp = wUserProps(pWin); pProp; pProp = pProp->next)
numProps++;
if (numProps && !(pAtoms = malloc(numProps * sizeof(Atom))))
return BadAlloc;
numProps = 0;
temppAtoms = pAtoms;
for (pProp = wUserProps(pWin); pProp; pProp = pProp->next) {
realProp = pProp;
rc = XaceHookPropertyAccess(client, pWin, &realProp, DixGetAttrAccess);
if (rc == Success && realProp == pProp) {
*temppAtoms++ = pProp->propertyName;
numProps++;
}
}
xlpr.type = X_Reply;
xlpr.nProperties = numProps;
xlpr.length = bytes_to_int32(numProps * sizeof(Atom));
xlpr.sequenceNumber = client->sequence;
WriteReplyToClient(client, sizeof(xGenericReply), &xlpr);
if (numProps)
{
client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
}
free(pAtoms);
return Success;
}
int
ProcDeleteProperty(ClientPtr client)
{
WindowPtr pWin;
REQUEST(xDeletePropertyReq);
int result;
REQUEST_SIZE_MATCH(xDeletePropertyReq);
UpdateCurrentTime();
result = dixLookupWindow(&pWin, stuff->window, client, DixSetPropAccess);
if (result != Success)
return result;
if (!ValidAtom(stuff->property))
{
client->errorValue = stuff->property;
return BadAtom;
}
return DeleteProperty(client, pWin, stuff->property);
}