054f8cd267
Add function to keep pointer within valid crtc areas. Finish event delivery and swapping code. Separate configuration from layout changes to send correct events.
432 lines
12 KiB
C
432 lines
12 KiB
C
/*
|
|
* Copyright © 2006 Keith Packard
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that copyright
|
|
* notice and this permission notice appear in supporting documentation, and
|
|
* that the name of the copyright holders not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. The copyright holders make no representations
|
|
* about the suitability of this software for any purpose. It is provided "as
|
|
* is" without express or implied warranty.
|
|
*
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include "randrstr.h"
|
|
#include "propertyst.h"
|
|
#include "swaprep.h"
|
|
|
|
static void
|
|
RRDeliverEvent (ScreenPtr pScreen, xEvent *event, CARD32 mask)
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
RRDeleteAllOutputProperties (RROutputPtr output)
|
|
{
|
|
PropertyPtr prop, next;
|
|
xRROutputPropertyNotifyEvent event;
|
|
|
|
for (prop = output->properties; prop; prop = next)
|
|
{
|
|
next = prop->next;
|
|
event.type = RREventBase + RRNotify;
|
|
event.subCode = RRNotify_OutputProperty;
|
|
event.output = output->id;
|
|
event.state = PropertyDelete;
|
|
event.atom = prop->propertyName;
|
|
event.timestamp = currentTime.milliseconds;
|
|
RRDeliverEvent (output->pScreen, (xEvent *) &event, RROutputPropertyNotifyMask);
|
|
xfree(prop->data);
|
|
xfree(prop);
|
|
}
|
|
}
|
|
|
|
void
|
|
RRDeleteOutputProperty (RROutputPtr output, Atom property)
|
|
{
|
|
PropertyPtr prop, *prev;
|
|
xRROutputPropertyNotifyEvent event;
|
|
|
|
for (prev = &output->properties; (prop = *prev); prev = &(prop->next))
|
|
if (prop->propertyName == property)
|
|
break;
|
|
if (prop)
|
|
{
|
|
*prev = prop->next;
|
|
event.type = RREventBase + RRNotify;
|
|
event.subCode = RRNotify_OutputProperty;
|
|
event.output = output->id;
|
|
event.state = PropertyDelete;
|
|
event.atom = prop->propertyName;
|
|
event.timestamp = currentTime.milliseconds;
|
|
RRDeliverEvent (output->pScreen, (xEvent *) &event, RROutputPropertyNotifyMask);
|
|
xfree(prop->data);
|
|
xfree(prop);
|
|
}
|
|
}
|
|
|
|
int
|
|
RRChangeOutputProperty (RROutputPtr output, Atom property, Atom type,
|
|
int format, int mode, unsigned long len,
|
|
pointer value, Bool sendevent)
|
|
{
|
|
PropertyPtr prop;
|
|
xRROutputPropertyNotifyEvent event;
|
|
int sizeInBytes;
|
|
int totalSize;
|
|
pointer data;
|
|
|
|
sizeInBytes = format >> 3;
|
|
totalSize = len * sizeInBytes;
|
|
|
|
/* first see if property already exists */
|
|
|
|
for (prop = output->properties; prop; prop = prop->next)
|
|
if (prop->propertyName == property)
|
|
break;
|
|
|
|
if (!prop) /* just add to list */
|
|
{
|
|
prop = (PropertyPtr)xalloc(sizeof(PropertyRec));
|
|
if (!prop)
|
|
return(BadAlloc);
|
|
data = (pointer)xalloc(totalSize);
|
|
if (!data && len)
|
|
{
|
|
xfree(prop);
|
|
return(BadAlloc);
|
|
}
|
|
prop->propertyName = property;
|
|
prop->type = type;
|
|
prop->format = format;
|
|
prop->data = data;
|
|
if (len)
|
|
memmove((char *)data, (char *)value, totalSize);
|
|
prop->size = len;
|
|
prop->next = output->properties;
|
|
output->properties = prop;
|
|
}
|
|
else
|
|
{
|
|
/* To append or prepend to a property the request format and type
|
|
must match those of the already defined property. The
|
|
existing format and type are irrelevant when using the mode
|
|
"PropModeReplace" since they will be written over. */
|
|
|
|
if ((format != prop->format) && (mode != PropModeReplace))
|
|
return(BadMatch);
|
|
if ((prop->type != type) && (mode != PropModeReplace))
|
|
return(BadMatch);
|
|
if (mode == PropModeReplace)
|
|
{
|
|
if (totalSize != prop->size * (prop->format >> 3))
|
|
{
|
|
data = (pointer)xrealloc(prop->data, totalSize);
|
|
if (!data && len)
|
|
return(BadAlloc);
|
|
prop->data = data;
|
|
}
|
|
if (len)
|
|
memmove((char *)prop->data, (char *)value, totalSize);
|
|
prop->size = len;
|
|
prop->type = type;
|
|
prop->format = format;
|
|
}
|
|
else if (len == 0)
|
|
{
|
|
/* do nothing */
|
|
}
|
|
else if (mode == PropModeAppend)
|
|
{
|
|
data = (pointer)xrealloc(prop->data,
|
|
sizeInBytes * (len + prop->size));
|
|
if (!data)
|
|
return(BadAlloc);
|
|
prop->data = data;
|
|
memmove(&((char *)data)[prop->size * sizeInBytes],
|
|
(char *)value,
|
|
totalSize);
|
|
prop->size += len;
|
|
}
|
|
else if (mode == PropModePrepend)
|
|
{
|
|
data = (pointer)xalloc(sizeInBytes * (len + prop->size));
|
|
if (!data)
|
|
return(BadAlloc);
|
|
memmove(&((char *)data)[totalSize], (char *)prop->data,
|
|
(int)(prop->size * sizeInBytes));
|
|
memmove((char *)data, (char *)value, totalSize);
|
|
xfree(prop->data);
|
|
prop->data = data;
|
|
prop->size += len;
|
|
}
|
|
}
|
|
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;
|
|
RRDeliverEvent (output->pScreen, (xEvent *) &event, RROutputPropertyNotifyMask);
|
|
}
|
|
return(Success);
|
|
}
|
|
|
|
int
|
|
ProcRRListOutputProperties (ClientPtr client)
|
|
{
|
|
REQUEST(xRRListOutputPropertiesReq);
|
|
Atom *pAtoms = NULL, *temppAtoms;
|
|
xRRListOutputPropertiesReply rep;
|
|
int numProps = 0;
|
|
RROutputPtr output;
|
|
PropertyPtr prop;
|
|
|
|
REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq);
|
|
|
|
output = LookupOutput (client, stuff->output, SecurityReadAccess);
|
|
|
|
if (!output)
|
|
return RRErrorBase + BadRROutput;
|
|
|
|
for (prop = output->properties; prop; prop = prop->next)
|
|
numProps++;
|
|
if (numProps)
|
|
if(!(pAtoms = (Atom *)ALLOCATE_LOCAL(numProps * sizeof(Atom))))
|
|
return(BadAlloc);
|
|
|
|
rep.type = X_Reply;
|
|
rep.nProperties = numProps;
|
|
rep.length = (numProps * sizeof(Atom)) >> 2;
|
|
rep.sequenceNumber = client->sequence;
|
|
temppAtoms = pAtoms;
|
|
for (prop = output->properties; prop; prop = prop->next)
|
|
*temppAtoms++ = prop->propertyName;
|
|
|
|
WriteReplyToClient(client, sizeof(xRRListOutputPropertiesReply), &rep);
|
|
if (numProps)
|
|
{
|
|
client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
|
|
WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
|
|
DEALLOCATE_LOCAL(pAtoms);
|
|
}
|
|
return(client->noClientException);
|
|
}
|
|
|
|
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 > ((0xffffffff - sizeof(xChangePropertyReq)) >> 2))
|
|
return BadLength;
|
|
sizeInBytes = format>>3;
|
|
totalSize = len * sizeInBytes;
|
|
REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq, totalSize);
|
|
|
|
output = LookupOutput (client, stuff->output, SecurityWriteAccess);
|
|
if (!output)
|
|
return RRErrorBase + BadRROutput;
|
|
|
|
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);
|
|
if (err != Success)
|
|
return err;
|
|
else
|
|
return client->noClientException;
|
|
}
|
|
|
|
int
|
|
ProcRRDeleteOutputProperty (ClientPtr client)
|
|
{
|
|
REQUEST(xRRDeleteOutputPropertyReq);
|
|
RROutputPtr output;
|
|
|
|
REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq);
|
|
UpdateCurrentTime();
|
|
output = LookupOutput (client, stuff->output, SecurityWriteAccess);
|
|
if (!output)
|
|
return RRErrorBase + BadRROutput;
|
|
|
|
if (!ValidAtom(stuff->property))
|
|
{
|
|
client->errorValue = stuff->property;
|
|
return (BadAtom);
|
|
}
|
|
|
|
|
|
RRDeleteOutputProperty(output, stuff->property);
|
|
return client->noClientException;
|
|
}
|
|
|
|
int
|
|
ProcRRGetOutputProperty (ClientPtr client)
|
|
{
|
|
REQUEST(xRRGetOutputPropertyReq);
|
|
PropertyPtr prop, *prev;
|
|
unsigned long n, len, ind;
|
|
RROutputPtr output;
|
|
xRRGetOutputPropertyReply reply;
|
|
|
|
REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq);
|
|
if (stuff->delete)
|
|
UpdateCurrentTime();
|
|
output = LookupOutput (client, stuff->output,
|
|
stuff->delete ? SecurityWriteAccess :
|
|
SecurityReadAccess);
|
|
if (!output)
|
|
return RRErrorBase + BadRROutput;
|
|
|
|
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;
|
|
WriteReplyToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
|
|
return(client->noClientException);
|
|
}
|
|
|
|
/* If the request type and actual type don't match. Return the
|
|
property information, but not the data. */
|
|
|
|
if (((stuff->type != prop->type) &&
|
|
(stuff->type != AnyPropertyType))
|
|
)
|
|
{
|
|
reply.bytesAfter = prop->size;
|
|
reply.format = prop->format;
|
|
reply.length = 0;
|
|
reply.nItems = 0;
|
|
reply.propertyType = prop->type;
|
|
WriteReplyToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
|
|
return(client->noClientException);
|
|
}
|
|
|
|
/*
|
|
* Return type, format, value to client
|
|
*/
|
|
n = (prop->format/8) * prop->size; /* size (bytes) of prop */
|
|
ind = stuff->longOffset << 2;
|
|
|
|
/* If longOffset is invalid such that it causes "len" to
|
|
be negative, it's a value error. */
|
|
|
|
if (n < ind)
|
|
{
|
|
client->errorValue = stuff->longOffset;
|
|
return BadValue;
|
|
}
|
|
|
|
len = min(n - ind, 4 * stuff->longLength);
|
|
|
|
reply.bytesAfter = n - (ind + len);
|
|
reply.format = prop->format;
|
|
reply.length = (len + 3) >> 2;
|
|
reply.nItems = len / (prop->format / 8 );
|
|
reply.propertyType = prop->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;
|
|
RRDeliverEvent (output->pScreen, (xEvent *) &event, RROutputPropertyNotifyMask);
|
|
}
|
|
|
|
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 *)prop->data + ind);
|
|
}
|
|
|
|
if (stuff->delete && (reply.bytesAfter == 0))
|
|
{ /* delete the Property */
|
|
*prev = prop->next;
|
|
xfree(prop->data);
|
|
xfree(prop);
|
|
}
|
|
return(client->noClientException);
|
|
}
|
|
|