#include "randrstr.h"
#include "propertyst.h"
#include "swaprep.h"
static int
DeliverPropertyEvent(WindowPtr pWin, void *value)
{
xRROutputPropertyNotifyEvent *event = value;
RREventPtr *pHead, pRREvent;
dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id,
RREventType, serverClient, DixReadAccess);
if (!pHead)
return WT_WALKCHILDREN;
for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next)
{
if (!(pRREvent->mask & RROutputPropertyNotifyMask))
continue;
event->window = pRREvent->window->drawable.id;
WriteEventsToClient(pRREvent->client, 1, (xEvent *)event);
}
return WT_WALKCHILDREN;
}
static void RRDeliverPropertyEvent(ScreenPtr pScreen, xEvent *event)
{
if (!(dispatchException & (DE_RESET | DE_TERMINATE)))
WalkTree(pScreen, DeliverPropertyEvent, event);
}
static void
RRDestroyOutputProperty (RRPropertyPtr prop)
{
free(prop->valid_values);
free(prop->current.data);
free(prop->pending.data);
free(prop);
}
static void
RRDeleteProperty(RROutputRec *output, RRPropertyRec *prop)
{
xRROutputPropertyNotifyEvent event;
event.type = RREventBase + RRNotify;
event.subCode = RRNotify_OutputProperty;
event.output = output->id;
event.state = PropertyDelete;
event.atom = prop->propertyName;
event.timestamp = currentTime.milliseconds;
RRDeliverPropertyEvent(output->pScreen, (xEvent *)&event);
RRDestroyOutputProperty(prop);
}
void
RRDeleteAllOutputProperties(RROutputPtr output)
{
RRPropertyPtr prop, next;
for (prop = output->properties; prop; prop = next) {
next = prop->next;
RRDeleteProperty(output, prop);
}
}
static void
RRInitOutputPropertyValue (RRPropertyValuePtr property_value)
{
property_value->type = None;
property_value->format = 0;
property_value->size = 0;
property_value->data = NULL;
}
static RRPropertyPtr
RRCreateOutputProperty (Atom property)
{
RRPropertyPtr prop;
prop = (RRPropertyPtr)malloc(sizeof(RRPropertyRec));
if (!prop)
return NULL;
prop->next = NULL;
prop->propertyName = property;
prop->is_pending = FALSE;
prop->range = FALSE;
prop->immutable = FALSE;
prop->num_valid = 0;
prop->valid_values = NULL;
RRInitOutputPropertyValue (&prop->current);
RRInitOutputPropertyValue (&prop->pending);
return prop;
}
void
RRDeleteOutputProperty(RROutputPtr output, Atom property)
{
RRPropertyRec *prop, **prev;
for (prev = &output->properties; (prop = *prev); prev = &(prop->next))
if (prop->propertyName == property) {
*prev = prop->next;
RRDeleteProperty(output, prop);
return;
}
}
int
RRChangeOutputProperty (RROutputPtr output, Atom property, Atom type,
int format, int mode, unsigned long len,
pointer value, Bool sendevent, Bool pending)
{
RRPropertyPtr prop;
xRROutputPropertyNotifyEvent event;
rrScrPrivPtr pScrPriv = rrGetScrPriv(output->pScreen);
int size_in_bytes;
int total_size;
unsigned long total_len;
RRPropertyValuePtr prop_value;
RRPropertyValueRec new_value;
Bool add = FALSE;
size_in_bytes = format >> 3;
prop = RRQueryOutputProperty (output, property);
if (!prop)
{
prop = RRCreateOutputProperty (property);
if (!prop)
return BadAlloc;
add = TRUE;
mode = PropModeReplace;
}
if (pending && prop->is_pending)
prop_value = &prop->pending;
else
prop_value = &prop->current;
if ((format != prop_value->format) && (mode != PropModeReplace))
return BadMatch;
if ((prop_value->type != type) && (mode != PropModeReplace))
return BadMatch;
new_value = *prop_value;
if (mode == PropModeReplace)
total_len = len;
else
total_len = prop_value->size + len;
if (mode == PropModeReplace || len > 0)
{
pointer new_data = NULL, old_data = NULL;
total_size = total_len * size_in_bytes;
new_value.data = (pointer)malloc(total_size);
if (!new_value.data && total_size)
{
if (add)
RRDestroyOutputProperty (prop);
return BadAlloc;
}
new_value.size = len;
new_value.type = type;
new_value.format = format;
switch (mode) {
case PropModeReplace:
new_data = new_value.data;
old_data = NULL;
break;
case PropModeAppend:
new_data = (pointer) (((char *) new_value.data) +
(prop_value->size * size_in_bytes));
old_data = new_value.data;
break;
case PropModePrepend:
new_data = new_value.data;
old_data = (pointer) (((char *) new_value.data) +
(prop_value->size * size_in_bytes));
break;
}
if (new_data)
memcpy ((char *) new_data, (char *) value, len * size_in_bytes);
if (old_data)
memcpy ((char *) old_data, (char *) prop_value->data,
prop_value->size * size_in_bytes);
if (pending && pScrPriv->rrOutputSetProperty &&
!pScrPriv->rrOutputSetProperty(output->pScreen, output,
prop->propertyName, &new_value))
{
free(new_value.data);
return BadValue;
}
free(prop_value->data);
*prop_value = new_value;
}
else if (len == 0)
{
}
if (add)
{
prop->next = output->properties;
output->properties = prop;
}
if (pending && prop->is_pending)
output->pendingProperties = TRUE;
if (sendevent)
{
event.type = RREventBase + RRNotify;
event.subCode = RRNotify_OutputProperty;
event.output = output->id;
event.state = PropertyNewValue;
event.atom = prop->propertyName;
event.timestamp = currentTime.milliseconds;
RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event);
}
return Success;
}
Bool
RRPostPendingProperties (RROutputPtr output)
{
RRPropertyValuePtr pending_value;
RRPropertyValuePtr current_value;
RRPropertyPtr property;
Bool ret = TRUE;
if (!output->pendingProperties)
return TRUE;
output->pendingProperties = FALSE;
for (property = output->properties; property; property = property->next)
{
if (!property->is_pending)
continue;
pending_value = &property->pending;
current_value = &property->current;
if (pending_value->type == current_value->type &&
pending_value->format == current_value->format &&
pending_value->size == current_value->size &&
!memcmp (pending_value->data, current_value->data,
pending_value->size * (pending_value->format / 8)))
continue;
if (RRChangeOutputProperty (output, property->propertyName,
pending_value->type, pending_value->format,
PropModeReplace, pending_value->size,
pending_value->data, TRUE,
FALSE) != Success)
ret = FALSE;
}
return ret;
}
RRPropertyPtr
RRQueryOutputProperty (RROutputPtr output, Atom property)
{
RRPropertyPtr prop;
for (prop = output->properties; prop; prop = prop->next)
if (prop->propertyName == property)
return prop;
return NULL;
}
RRPropertyValuePtr
RRGetOutputProperty (RROutputPtr output, Atom property, Bool pending)
{
RRPropertyPtr prop = RRQueryOutputProperty (output, property);
rrScrPrivPtr pScrPriv = rrGetScrPriv(output->pScreen);
if (!prop)
return NULL;
if (pending && prop->is_pending)
return &prop->pending;
else {
#if RANDR_13_INTERFACE
if (pScrPriv->rrOutputGetProperty)
pScrPriv->rrOutputGetProperty(output->pScreen, output,
prop->propertyName);
#endif
return &prop->current;
}
}
int
RRConfigureOutputProperty (RROutputPtr output, Atom property,
Bool pending, Bool range, Bool immutable,
int num_values, INT32 *values)
{
RRPropertyPtr prop = RRQueryOutputProperty (output, property);
Bool add = FALSE;
INT32 *new_values;
if (!prop)
{
prop = RRCreateOutputProperty (property);
if (!prop)
return BadAlloc;
add = TRUE;
} else if (prop->immutable && !immutable)
return BadAccess;
if (range && (num_values & 1))
return BadMatch;
new_values = malloc(num_values * sizeof (INT32));
if (!new_values && num_values)
return BadAlloc;
if (num_values)
memcpy (new_values, values, num_values * sizeof (INT32));
if (prop->is_pending && !pending)
{
free(prop->pending.data);
RRInitOutputPropertyValue (&prop->pending);
}
prop->is_pending = pending;
prop->range = range;
prop->immutable = immutable;
prop->num_valid = num_values;
free(prop->valid_values);
prop->valid_values = new_values;
if (add) {
prop->next = output->properties;
output->properties = prop;
}
return Success;
}
int
ProcRRListOutputProperties (ClientPtr client)
{
REQUEST(xRRListOutputPropertiesReq);
Atom *pAtoms = NULL, *temppAtoms;
xRRListOutputPropertiesReply rep;
int numProps = 0;
RROutputPtr output;
RRPropertyPtr prop;
REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq);
VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
for (prop = output->properties; prop; prop = prop->next)
numProps++;
if (numProps)
if(!(pAtoms = (Atom *)malloc(numProps * sizeof(Atom))))
return BadAlloc;
rep.type = X_Reply;
rep.length = bytes_to_int32(numProps * sizeof(Atom));
rep.sequenceNumber = client->sequence;
rep.nAtoms = numProps;
if (client->swapped)
{
int n;
swaps (&rep.sequenceNumber, n);
swapl (&rep.length, n);
swaps (&rep.nAtoms, n);
}
temppAtoms = pAtoms;
for (prop = output->properties; prop; prop = prop->next)
*temppAtoms++ = prop->propertyName;
WriteToClient(client, sizeof(xRRListOutputPropertiesReply), (char*)&rep);
if (numProps)
{
client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
free(pAtoms);
}
return Success;
}
int
ProcRRQueryOutputProperty (ClientPtr client)
{
REQUEST(xRRQueryOutputPropertyReq);
xRRQueryOutputPropertyReply rep;
RROutputPtr output;
RRPropertyPtr prop;
char *extra = NULL;
REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq);
VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
prop = RRQueryOutputProperty (output, stuff->property);
if (!prop)
return BadName;
if (prop->num_valid) {
extra = malloc(prop->num_valid * sizeof(INT32));
if (!extra)
return BadAlloc;
}
rep.type = X_Reply;
rep.length = prop->num_valid;
rep.sequenceNumber = client->sequence;
rep.pending = prop->is_pending;
rep.range = prop->range;
rep.immutable = prop->immutable;
if (client->swapped)
{
int n;
swaps (&rep.sequenceNumber, n);
swapl (&rep.length, n);
}
WriteToClient (client, sizeof (xRRQueryOutputPropertyReply), (char*)&rep);
if (prop->num_valid)
{
memcpy(extra, prop->valid_values, prop->num_valid * sizeof(INT32));
client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32),
extra);
free(extra);
}
return Success;
}
int
ProcRRConfigureOutputProperty (ClientPtr client)
{
REQUEST(xRRConfigureOutputPropertyReq);
RROutputPtr output;
int num_valid;
REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq);
VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
num_valid = stuff->length - bytes_to_int32(sizeof (xRRConfigureOutputPropertyReq));
return RRConfigureOutputProperty (output, stuff->property,
stuff->pending, stuff->range,
FALSE, num_valid,
(INT32 *) (stuff + 1));
}
int
ProcRRChangeOutputProperty (ClientPtr client)
{
REQUEST(xRRChangeOutputPropertyReq);
RROutputPtr output;
char format, mode;
unsigned long len;
int sizeInBytes;
int totalSize;
int err;
REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq);
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(xRRChangeOutputPropertyReq, totalSize);
VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
if (!ValidAtom(stuff->property))
{
client->errorValue = stuff->property;
return BadAtom;
}
if (!ValidAtom(stuff->type))
{
client->errorValue = stuff->type;
return BadAtom;
}
err = RRChangeOutputProperty(output, stuff->property,
stuff->type, (int)format,
(int)mode, len, (pointer)&stuff[1], TRUE, TRUE);
if (err != Success)
return err;
else
return Success;
}
int
ProcRRDeleteOutputProperty (ClientPtr client)
{
REQUEST(xRRDeleteOutputPropertyReq);
RROutputPtr output;
REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq);
UpdateCurrentTime();
VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
if (!ValidAtom(stuff->property))
{
client->errorValue = stuff->property;
return BadAtom;
}
RRDeleteOutputProperty(output, stuff->property);
return Success;
}
int
ProcRRGetOutputProperty (ClientPtr client)
{
REQUEST(xRRGetOutputPropertyReq);
RRPropertyPtr prop, *prev;
RRPropertyValuePtr prop_value;
unsigned long n, len, ind;
RROutputPtr output;
xRRGetOutputPropertyReply reply;
char *extra = NULL;
REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq);
if (stuff->delete)
UpdateCurrentTime();
VERIFY_RR_OUTPUT(stuff->output, output,
stuff->delete ? DixWriteAccess : DixReadAccess);
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;
}
for (prev = &output->properties; (prop = *prev); prev = &prop->next)
if (prop->propertyName == stuff->property)
break;
reply.type = X_Reply;
reply.sequenceNumber = client->sequence;
if (!prop)
{
reply.nItems = 0;
reply.length = 0;
reply.bytesAfter = 0;
reply.propertyType = None;
reply.format = 0;
if (client->swapped) {
int n;
swaps(&reply.sequenceNumber, n);
swapl(&reply.length, n);
swapl(&reply.propertyType, n);
swapl(&reply.bytesAfter, n);
swapl(&reply.nItems, n);
}
WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
return Success;
}
if (prop->immutable && stuff->delete)
return BadAccess;
prop_value = RRGetOutputProperty(output, stuff->property, stuff->pending);
if (!prop_value)
return BadAtom;
if (((stuff->type != prop_value->type) &&
(stuff->type != AnyPropertyType))
)
{
reply.bytesAfter = prop_value->size;
reply.format = prop_value->format;
reply.length = 0;
reply.nItems = 0;
reply.propertyType = prop_value->type;
if (client->swapped) {
int n;
swaps(&reply.sequenceNumber, n);
swapl(&reply.length, n);
swapl(&reply.propertyType, n);
swapl(&reply.bytesAfter, n);
swapl(&reply.nItems, n);
}
WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
return Success;
}
n = (prop_value->format/8) * prop_value->size;
ind = stuff->longOffset << 2;
if (n < ind)
{
client->errorValue = stuff->longOffset;
return BadValue;
}
len = min(n - ind, 4 * stuff->longLength);
if (len) {
extra = malloc(len);
if (!extra)
return BadAlloc;
}
reply.bytesAfter = n - (ind + len);
reply.format = prop_value->format;
reply.length = bytes_to_int32(len);
if (prop_value->format)
reply.nItems = len / (prop_value->format / 8);
else
reply.nItems = 0;
reply.propertyType = prop_value->type;
if (stuff->delete && (reply.bytesAfter == 0))
{
xRROutputPropertyNotifyEvent event;
event.type = RREventBase + RRNotify;
event.subCode = RRNotify_OutputProperty;
event.output = output->id;
event.state = PropertyDelete;
event.atom = prop->propertyName;
event.timestamp = currentTime.milliseconds;
RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event);
}
if (client->swapped) {
int n;
swaps(&reply.sequenceNumber, n);
swapl(&reply.length, n);
swapl(&reply.propertyType, n);
swapl(&reply.bytesAfter, n);
swapl(&reply.nItems, n);
}
WriteToClient(client, sizeof(xGenericReply), &reply);
if (len)
{
memcpy(extra, (char *)prop_value->data + ind, 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,
extra);
free(extra);
}
if (stuff->delete && (reply.bytesAfter == 0))
{
*prev = prop->next;
RRDestroyOutputProperty (prop);
}
return Success;
}