From 66d92afeaeed9f4a19267d95a1f81b9bf27162a5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Jun 2012 14:03:04 +0100 Subject: randr: add provider object and provider property support (v6) This adds the initial provider object and provider property support to the randr dix code. v2: destroy provider in screen close v2.1: fix whitespace v3: update for latest rev of protocol + renumber after 1.4 tearout. v4: fix logic issue, thanks Samsagax on irc v5: keithp's review: fix current_role, fix copyrights, fix master reporting crtc/outputs. v6: port to new randr interface, drop all set role bits for now v7: drop devPrivate in provider, not needed, add BadMatch returns for NULL SetProviderOffloadSink and SetProviderOutputSource, drop the old typedef. Reviewed-by: Keith Packard Reviewed-by: Adam Jackson Signed-off-by: Dave Airlie --- hw/xfree86/common/xf86platformBus.c | 9 +- randr/Makefile.am | 2 + randr/randr.c | 57 ++- randr/randrstr.h | 98 ++++- randr/rrdispatch.c | 14 +- randr/rrprovider.c | 279 ++++++++++++++ randr/rrproviderproperty.c | 716 ++++++++++++++++++++++++++++++++++++ 7 files changed, 1169 insertions(+), 6 deletions(-) create mode 100644 randr/rrprovider.c create mode 100644 randr/rrproviderproperty.c diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c index 3bfb22e83..24b947326 100644 --- a/hw/xfree86/common/xf86platformBus.c +++ b/hw/xfree86/common/xf86platformBus.c @@ -432,14 +432,17 @@ xf86platformAddDevice(int index) xf86DeleteScreen(xf86GPUScreens[i]); return -1; } - + scr_index = AddGPUScreen(xf86GPUScreens[i]->ScreenInit, 0, NULL); - + dixSetPrivate(&xf86GPUScreens[i]->pScreen->devPrivates, xf86ScreenKey, xf86GPUScreens[i]); CreateScratchPixmapsForScreen(xf86GPUScreens[i]->pScreen); - + + /* attach unbound to 0 protocol screen */ + AttachUnboundGPU(xf86Screens[0]->pScreen, xf86GPUScreens[i]->pScreen); + return 0; } diff --git a/randr/Makefile.am b/randr/Makefile.am index de338b972..ccaff3f02 100644 --- a/randr/Makefile.am +++ b/randr/Makefile.am @@ -18,6 +18,8 @@ librandr_la_SOURCES = \ rroutput.c \ rrpointer.c \ rrproperty.c \ + rrprovider.c \ + rrproviderproperty.c \ rrscreen.c \ rrsdispatch.c \ rrtransform.h \ diff --git a/randr/randr.c b/randr/randr.c index 103da48d7..103c31e31 100644 --- a/randr/randr.c +++ b/randr/randr.c @@ -94,6 +94,9 @@ RRCloseScreen(ScreenPtr pScreen) for (j = pScrPriv->numOutputs - 1; j >= 0; j--) RROutputDestroy(pScrPriv->outputs[j]); + if (pScrPriv->provider) + RRProviderDestroy(pScrPriv->provider); + free(pScrPriv->crtcs); free(pScrPriv->outputs); free(pScrPriv); @@ -175,6 +178,47 @@ SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent * from, /* pad4 */ } +static void +SRRProviderChangeNotifyEvent(xRRProviderChangeNotifyEvent * from, + xRRProviderChangeNotifyEvent * to) +{ + to->type = from->type; + to->subCode = from->subCode; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->timestamp, to->timestamp); + cpswapl(from->window, to->window); + cpswapl(from->provider, to->provider); +} + +static void +SRRProviderPropertyNotifyEvent(xRRProviderPropertyNotifyEvent * from, + xRRProviderPropertyNotifyEvent * to) +{ + to->type = from->type; + to->subCode = from->subCode; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->window, to->window); + cpswapl(from->provider, to->provider); + cpswapl(from->atom, to->atom); + cpswapl(from->timestamp, to->timestamp); + to->state = from->state; + /* pad1 */ + /* pad2 */ + /* pad3 */ + /* pad4 */ +} + +static void +SRRResourceChangeNotifyEvent(xRRResourceChangeNotifyEvent * from, + xRRResourceChangeNotifyEvent * to) +{ + to->type = from->type; + to->subCode = from->subCode; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->timestamp, to->timestamp); + cpswapl(from->window, to->window); +} + static void SRRNotifyEvent(xEvent *from, xEvent *to) { @@ -191,6 +235,17 @@ SRRNotifyEvent(xEvent *from, xEvent *to) SRROutputPropertyNotifyEvent((xRROutputPropertyNotifyEvent *) from, (xRROutputPropertyNotifyEvent *) to); break; + case RRNotify_ProviderChange: + SRRProviderChangeNotifyEvent((xRRProviderChangeNotifyEvent *) from, + (xRRProviderChangeNotifyEvent *) to); + break; + case RRNotify_ProviderProperty: + SRRProviderPropertyNotifyEvent((xRRProviderPropertyNotifyEvent *) from, + (xRRProviderPropertyNotifyEvent *) to); + break; + case RRNotify_ResourceChange: + SRRResourceChangeNotifyEvent((xRRResourceChangeNotifyEvent *) from, + (xRRResourceChangeNotifyEvent *) to); default: break; } @@ -356,7 +411,7 @@ RRExtensionInit(void) RRModeInitErrorValue(); RRCrtcInitErrorValue(); RROutputInitErrorValue(); - + RRProviderInitErrorValue(); #ifdef PANORAMIX RRXineramaExtensionInit(); #endif diff --git a/randr/randrstr.h b/randr/randrstr.h index 38fb10751..3dac63326 100644 --- a/randr/randrstr.h +++ b/randr/randrstr.h @@ -62,6 +62,7 @@ typedef XID RRMode; typedef XID RROutput; typedef XID RRCrtc; +typedef XID RRProvider; extern _X_EXPORT int RREventBase, RRErrorBase; @@ -78,6 +79,7 @@ typedef struct _rrPropertyValue RRPropertyValueRec, *RRPropertyValuePtr; typedef struct _rrProperty RRPropertyRec, *RRPropertyPtr; typedef struct _rrCrtc RRCrtcRec, *RRCrtcPtr; typedef struct _rrOutput RROutputRec, *RROutputPtr; +typedef struct _rrProvider RRProviderRec, *RRProviderPtr; struct _rrMode { int refcnt; @@ -152,6 +154,16 @@ struct _rrOutput { void *devPrivate; }; +struct _rrProvider { + RRProvider id; + ScreenPtr pScreen; + uint32_t capabilities; + char *name; + int nameLength; + RRPropertyPtr properties; + Bool pendingProperties; +}; + #if RANDR_12_INTERFACE typedef Bool (*RRScreenSetSizeProcPtr) (ScreenPtr pScreen, CARD16 width, @@ -197,6 +209,13 @@ typedef Bool (*RRSetPanningProcPtr) (ScreenPtr pScrn, #endif /* RANDR_13_INTERFACE */ +typedef Bool (*RRProviderGetPropertyProcPtr) (ScreenPtr pScreen, + RRProviderPtr provider, Atom property); +typedef Bool (*RRProviderSetPropertyProcPtr) (ScreenPtr pScreen, + RRProviderPtr provider, + Atom property, + RRPropertyValuePtr value); + typedef Bool (*RRGetInfoProcPtr) (ScreenPtr pScreen, Rotation * rotations); typedef Bool (*RRCloseScreenProcPtr) (ScreenPtr pscreen); @@ -247,6 +266,8 @@ typedef struct _rrScrPriv { RRSetPanningProcPtr rrSetPanning; #endif + RRProviderGetPropertyProcPtr rrProviderGetProperty; + RRProviderSetPropertyProcPtr rrProviderSetProperty; /* * Private part of the structure; not considered part of the ABI */ @@ -288,6 +309,8 @@ typedef struct _rrScrPriv { int size; #endif Bool discontiguous; + + RRProviderPtr provider; } rrScrPrivRec, *rrScrPrivPtr; extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec; @@ -331,7 +354,7 @@ extern _X_EXPORT RESTYPE RRClientType, RREventType; /* resource types for ev extern _X_EXPORT DevPrivateKeyRec RRClientPrivateKeyRec; #define RRClientPrivateKey (&RRClientPrivateKeyRec) -extern _X_EXPORT RESTYPE RRCrtcType, RRModeType, RROutputType; +extern _X_EXPORT RESTYPE RRCrtcType, RRModeType, RROutputType, RRProviderType; #define VERIFY_RR_OUTPUT(id, ptr, a)\ {\ @@ -363,6 +386,16 @@ extern _X_EXPORT RESTYPE RRCrtcType, RRModeType, RROutputType; }\ } +#define VERIFY_RR_PROVIDER(id, ptr, a)\ + {\ + int rc = dixLookupResourceByType((pointer *)&(ptr), id,\ + RRProviderType, client, a);\ + if (rc != Success) {\ + client->errorValue = id;\ + return rc;\ + }\ + } + #define GetRRClient(pClient) ((RRClientPtr)dixLookupPrivate(&(pClient)->devPrivates, RRClientPrivateKey)) #define rrClientPriv(pClient) RRClientPtr pRRClient = GetRRClient(pClient) @@ -824,6 +857,69 @@ extern _X_EXPORT int extern _X_EXPORT int ProcRRDeleteOutputProperty(ClientPtr client); +/* rrprovider.c */ +extern _X_EXPORT void +RRProviderInitErrorValue(void); + +extern _X_EXPORT int +ProcRRGetProviders(ClientPtr client); + +extern _X_EXPORT int +ProcRRGetProviderInfo(ClientPtr client); + + +extern _X_EXPORT Bool +RRProviderInit(void); + +extern _X_EXPORT RRProviderPtr +RRProviderCreate(ScreenPtr pScreen, const char *name, + int nameLength); + +extern _X_EXPORT void +RRProviderDestroy (RRProviderPtr provider); + +extern _X_EXPORT void +RRProviderSetCapabilities(RRProviderPtr provider, uint32_t capabilities); + +extern _X_EXPORT Bool +RRProviderLookup(XID id, RRProviderPtr *provider_p); + +/* rrproviderproperty.c */ + +extern _X_EXPORT void + RRDeleteAllProviderProperties(RRProviderPtr provider); + +extern _X_EXPORT RRPropertyValuePtr + RRGetProviderProperty(RRProviderPtr provider, Atom property, Bool pending); + +extern _X_EXPORT RRPropertyPtr + RRQueryProviderProperty(RRProviderPtr provider, Atom property); + +extern _X_EXPORT void + RRDeleteProviderProperty(RRProviderPtr provider, Atom property); + +extern _X_EXPORT int +RRChangeProviderProperty(RRProviderPtr provider, Atom property, Atom type, + int format, int mode, unsigned long len, + pointer value, Bool sendevent, Bool pending); + +extern _X_EXPORT int + ProcRRGetProviderProperty(ClientPtr client); + +extern _X_EXPORT int + ProcRRListProviderProperties(ClientPtr client); + +extern _X_EXPORT int + ProcRRQueryProviderProperty(ClientPtr client); + +extern _X_EXPORT int +ProcRRConfigureProviderProperty(ClientPtr client); + +extern _X_EXPORT int +ProcRRChangeProviderProperty(ClientPtr client); + +extern _X_EXPORT int + ProcRRDeleteProviderProperty(ClientPtr client); /* rrxinerama.c */ #ifdef XINERAMA extern _X_EXPORT void diff --git a/randr/rrdispatch.c b/randr/rrdispatch.c index 85cf03738..054e47a7a 100644 --- a/randr/rrdispatch.c +++ b/randr/rrdispatch.c @@ -90,7 +90,8 @@ ProcRRSelectInput(ClientPtr client) if (stuff->enable & (RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | - RROutputPropertyNotifyMask)) { + RROutputPropertyNotifyMask | + RRProviderPropertyNotifyMask)) { ScreenPtr pScreen = pWin->drawable.pScreen; rrScrPriv(pScreen); @@ -241,4 +242,15 @@ int (*ProcRandrVector[RRNumberRequests]) (ClientPtr) = { ProcRRSetPanning, /* 29 */ ProcRRSetOutputPrimary, /* 30 */ ProcRRGetOutputPrimary, /* 31 */ +/* V1.4 additions */ + ProcRRGetProviders, /* 32 */ + ProcRRGetProviderInfo, /* 33 */ + NULL, /* 34 */ + NULL, /* 35 */ + ProcRRListProviderProperties, /* 36 */ + ProcRRQueryProviderProperty, /* 37 */ + ProcRRConfigureProviderProperty, /* 38 */ + ProcRRChangeProviderProperty, /* 39 */ + ProcRRDeleteProviderProperty, /* 40 */ + ProcRRGetProviderProperty, /* 41 */ }; diff --git a/randr/rrprovider.c b/randr/rrprovider.c new file mode 100644 index 000000000..db7074c40 --- /dev/null +++ b/randr/rrprovider.c @@ -0,0 +1,279 @@ +/* + * Copyright © 2012 Red Hat Inc. + * + * 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. + * + * Authors: Dave Airlie + */ + +#include "randrstr.h" +#include "swaprep.h" + +RESTYPE RRProviderType; + +/* + * Initialize provider type error value + */ +void +RRProviderInitErrorValue(void) +{ + SetResourceTypeErrorValue(RRProviderType, RRErrorBase + BadRRProvider); +} + +#define ADD_PROVIDER(_pScreen) do { \ + pScrPriv = rrGetScrPriv((_pScreen)); \ + if (pScrPriv->provider) { \ + providers[count_providers] = pScrPriv->provider->id; \ + if (client->swapped) \ + swapl(&providers[count_providers]); \ + count_providers++; \ + } \ + } while(0) + +int +ProcRRGetProviders (ClientPtr client) +{ + REQUEST(xRRGetProvidersReq); + xRRGetProvidersReply rep; + WindowPtr pWin; + ScreenPtr pScreen; + rrScrPrivPtr pScrPriv; + int rc; + CARD8 *extra; + unsigned int extraLen; + RRProvider *providers; + int total_providers = 0, count_providers = 0; + + REQUEST_SIZE_MATCH(xRRGetProvidersReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + pScreen = pWin->drawable.pScreen; + + pScrPriv = rrGetScrPriv(pScreen); + + if (pScrPriv->provider) + total_providers++; + + pScrPriv = rrGetScrPriv(pScreen); + rep.pad = 0; + + if (!pScrPriv) + { + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.timestamp = currentTime.milliseconds; + rep.nProviders = 0; + extra = NULL; + extraLen = 0; + } else { + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.timestamp = pScrPriv->lastSetTime.milliseconds; + rep.nProviders = total_providers; + rep.length = total_providers; + extraLen = rep.length << 2; + if (extraLen) { + extra = malloc(extraLen); + if (!extra) + return BadAlloc; + } else + extra = NULL; + + providers = (RRProvider *)extra; + ADD_PROVIDER(pScreen); + } + + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.timestamp); + swaps(&rep.nProviders); + } + WriteToClient(client, sizeof(xRRGetProvidersReply), (char *)&rep); + if (extraLen) + { + WriteToClient (client, extraLen, (char *) extra); + free(extra); + } + return Success; +} + +int +ProcRRGetProviderInfo (ClientPtr client) +{ + REQUEST(xRRGetProviderInfoReq); + xRRGetProviderInfoReply rep; + rrScrPrivPtr pScrPriv; + RRProviderPtr provider; + ScreenPtr pScreen; + CARD8 *extra; + unsigned int extraLen = 0; + RRCrtc *crtcs; + RROutput *outputs; + int i; + char *name; + ScreenPtr provscreen; + RRProvider *providers; + uint32_t *prov_cap; + + REQUEST_SIZE_MATCH(xRRGetProviderInfoReq); + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + pScreen = provider->pScreen; + pScrPriv = rrGetScrPriv(pScreen); + + rep.type = X_Reply; + rep.status = RRSetConfigSuccess; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.capabilities = provider->capabilities; + rep.nameLength = provider->nameLength; + rep.timestamp = pScrPriv->lastSetTime.milliseconds; + rep.nCrtcs = pScrPriv->numCrtcs; + rep.nOutputs = pScrPriv->numOutputs; + + /* count associated providers */ + rep.nAssociatedProviders = 0; + rep.length = (pScrPriv->numCrtcs + pScrPriv->numOutputs + + (rep.nAssociatedProviders * 2) + bytes_to_int32(rep.nameLength)); + + extraLen = rep.length << 2; + if (extraLen) { + extra = malloc(extraLen); + if (!extra) + return BadAlloc; + } + else + extra = NULL; + + crtcs = (RRCrtc *)extra; + outputs = (RROutput *)(crtcs + rep.nCrtcs); + providers = (RRProvider *)(outputs + rep.nOutputs); + prov_cap = (unsigned int *)(providers + rep.nAssociatedProviders); + name = (char *)(prov_cap + rep.nAssociatedProviders); + + for (i = 0; i < pScrPriv->numCrtcs; i++) { + crtcs[i] = pScrPriv->crtcs[i]->id; + if (client->swapped) + swapl(&crtcs[i]); + } + + for (i = 0; i < pScrPriv->numOutputs; i++) { + outputs[i] = pScrPriv->outputs[i]->id; + if (client->swapped) + swapl(&outputs[i]); + } + + memcpy(name, provider->name, rep.nameLength); + if (client->swapped) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swapl(&rep.capabilities); + swaps(&rep.nCrtcs); + swaps(&rep.nOutputs); + swaps(&rep.nameLength); + } + WriteToClient(client, sizeof(xRRGetProviderInfoReply), (char *)&rep); + if (extraLen) + { + WriteToClient (client, extraLen, (char *) extra); + free(extra); + } + return Success; +} + +RRProviderPtr +RRProviderCreate(ScreenPtr pScreen, const char *name, + int nameLength) +{ + RRProviderPtr provider; + rrScrPrivPtr pScrPriv; + + pScrPriv = rrGetScrPriv(pScreen); + + provider = calloc(1, sizeof(RRProviderRec) + nameLength + 1); + if (!provider) + return NULL; + + provider->id = FakeClientID(0); + provider->pScreen = pScreen; + provider->name = (char *) (provider + 1); + provider->nameLength = nameLength; + memcpy(provider->name, name, nameLength); + provider->name[nameLength] = '\0'; + + if (!AddResource (provider->id, RRProviderType, (pointer) provider)) + return NULL; + pScrPriv->provider = provider; + return provider; +} + +/* + * Destroy a provider at shutdown + */ +void +RRProviderDestroy (RRProviderPtr provider) +{ + FreeResource (provider->id, 0); +} + +void +RRProviderSetCapabilities(RRProviderPtr provider, uint32_t capabilities) +{ + provider->capabilities = capabilities; +} + +static int +RRProviderDestroyResource (pointer value, XID pid) +{ + RRProviderPtr provider = (RRProviderPtr)value; + ScreenPtr pScreen = provider->pScreen; + + if (pScreen) + { + rrScrPriv(pScreen); + + pScrPriv->provider = NULL; + } + free(provider); + return 1; +} + +Bool +RRProviderInit(void) +{ + RRProviderType = CreateNewResourceType(RRProviderDestroyResource, "Provider"); + if (!RRProviderType) + return FALSE; + + return TRUE; +} + +extern _X_EXPORT Bool +RRProviderLookup(XID id, RRProviderPtr *provider_p) +{ + int rc = dixLookupResourceByType((void **)provider_p, id, + RRProviderType, NullClient, DixReadAccess); + if (rc == Success) + return TRUE; + return FALSE; +} diff --git a/randr/rrproviderproperty.c b/randr/rrproviderproperty.c new file mode 100644 index 000000000..5e04fab8f --- /dev/null +++ b/randr/rrproviderproperty.c @@ -0,0 +1,716 @@ +/* + * 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 int +DeliverPropertyEvent(WindowPtr pWin, void *value) +{ + xRRProviderPropertyNotifyEvent *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 & RRProviderPropertyNotifyMask)) + 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 +RRDestroyProviderProperty(RRPropertyPtr prop) +{ + free(prop->valid_values); + free(prop->current.data); + free(prop->pending.data); + free(prop); +} + +static void +RRDeleteProperty(RRProviderRec * provider, RRPropertyRec * prop) +{ + xRRProviderPropertyNotifyEvent event; + + event.type = RREventBase + RRNotify; + event.subCode = RRNotify_ProviderProperty; + event.provider = provider->id; + event.state = PropertyDelete; + event.atom = prop->propertyName; + event.timestamp = currentTime.milliseconds; + + RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event); + + RRDestroyProviderProperty(prop); +} + +void +RRDeleteAllProviderProperties(RRProviderPtr provider) +{ + RRPropertyPtr prop, next; + + for (prop = provider->properties; prop; prop = next) { + next = prop->next; + RRDeleteProperty(provider, prop); + } +} + +static void +RRInitProviderPropertyValue(RRPropertyValuePtr property_value) +{ + property_value->type = None; + property_value->format = 0; + property_value->size = 0; + property_value->data = NULL; +} + +static RRPropertyPtr +RRCreateProviderProperty(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; + RRInitProviderPropertyValue(&prop->current); + RRInitProviderPropertyValue(&prop->pending); + return prop; +} + +void +RRDeleteProviderProperty(RRProviderPtr provider, Atom property) +{ + RRPropertyRec *prop, **prev; + + for (prev = &provider->properties; (prop = *prev); prev = &(prop->next)) + if (prop->propertyName == property) { + *prev = prop->next; + RRDeleteProperty(provider, prop); + return; + } +} + +int +RRChangeProviderProperty(RRProviderPtr provider, Atom property, Atom type, + int format, int mode, unsigned long len, + pointer value, Bool sendevent, Bool pending) +{ + RRPropertyPtr prop; + xRRProviderPropertyNotifyEvent event; + rrScrPrivPtr pScrPriv = rrGetScrPriv(provider->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; + + /* first see if property already exists */ + prop = RRQueryProviderProperty(provider, property); + if (!prop) { /* just add to list */ + prop = RRCreateProviderProperty(property); + if (!prop) + return BadAlloc; + add = TRUE; + mode = PropModeReplace; + } + if (pending && prop->is_pending) + prop_value = &prop->pending; + else + prop_value = &prop->current; + + /* 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_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) + RRDestroyProviderProperty(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->rrProviderSetProperty && + !pScrPriv->rrProviderSetProperty(provider->pScreen, provider, + prop->propertyName, &new_value)) { + free(new_value.data); + return BadValue; + } + free(prop_value->data); + *prop_value = new_value; + } + + else if (len == 0) { + /* do nothing */ + } + + if (add) { + prop->next = provider->properties; + provider->properties = prop; + } + + if (pending && prop->is_pending) + provider->pendingProperties = TRUE; + + if (sendevent) { + event.type = RREventBase + RRNotify; + event.subCode = RRNotify_ProviderProperty; + event.provider = provider->id; + event.state = PropertyNewValue; + event.atom = prop->propertyName; + event.timestamp = currentTime.milliseconds; + RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event); + } + return Success; +} + +Bool +RRPostProviderPendingProperties(RRProviderPtr provider) +{ + RRPropertyValuePtr pending_value; + RRPropertyValuePtr current_value; + RRPropertyPtr property; + Bool ret = TRUE; + + if (!provider->pendingProperties) + return TRUE; + + provider->pendingProperties = FALSE; + for (property = provider->properties; property; property = property->next) { + /* Skip non-pending properties */ + if (!property->is_pending) + continue; + + pending_value = &property->pending; + current_value = &property->current; + + /* + * If the pending and current values are equal, don't mark it + * as changed (which would deliver an event) + */ + 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 (RRChangeProviderProperty(provider, property->propertyName, + pending_value->type, pending_value->format, + PropModeReplace, pending_value->size, + pending_value->data, TRUE, FALSE) != Success) + ret = FALSE; + } + return ret; +} + +RRPropertyPtr +RRQueryProviderProperty(RRProviderPtr provider, Atom property) +{ + RRPropertyPtr prop; + + for (prop = provider->properties; prop; prop = prop->next) + if (prop->propertyName == property) + return prop; + return NULL; +} + +RRPropertyValuePtr +RRGetProviderProperty(RRProviderPtr provider, Atom property, Bool pending) +{ + RRPropertyPtr prop = RRQueryProviderProperty(provider, property); + rrScrPrivPtr pScrPriv = rrGetScrPriv(provider->pScreen); + + if (!prop) + return NULL; + if (pending && prop->is_pending) + return &prop->pending; + else { +#if RANDR_13_INTERFACE + /* If we can, try to update the property value first */ + if (pScrPriv->rrProviderGetProperty) + pScrPriv->rrProviderGetProperty(provider->pScreen, provider, + prop->propertyName); +#endif + return &prop->current; + } +} + +int +RRConfigureProviderProperty(RRProviderPtr provider, Atom property, + Bool pending, Bool range, Bool immutable, + int num_values, INT32 *values) +{ + RRPropertyPtr prop = RRQueryProviderProperty(provider, property); + Bool add = FALSE; + INT32 *new_values; + + if (!prop) { + prop = RRCreateProviderProperty(property); + if (!prop) + return BadAlloc; + add = TRUE; + } + else if (prop->immutable && !immutable) + return BadAccess; + + /* + * ranges must have even number of values + */ + 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)); + + /* + * Property moving from pending to non-pending + * loses any pending values + */ + if (prop->is_pending && !pending) { + free(prop->pending.data); + RRInitProviderPropertyValue(&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 = provider->properties; + provider->properties = prop; + } + + return Success; +} + +int +ProcRRListProviderProperties(ClientPtr client) +{ + REQUEST(xRRListProviderPropertiesReq); + Atom *pAtoms = NULL, *temppAtoms; + xRRListProviderPropertiesReply rep; + int numProps = 0; + RRProviderPtr provider; + RRPropertyPtr prop; + + REQUEST_SIZE_MATCH(xRRListProviderPropertiesReq); + + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + for (prop = provider->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) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + swaps(&rep.nAtoms); + } + temppAtoms = pAtoms; + for (prop = provider->properties; prop; prop = prop->next) + *temppAtoms++ = prop->propertyName; + + WriteToClient(client, sizeof(xRRListProviderPropertiesReply), (char *) &rep); + if (numProps) { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); + free(pAtoms); + } + return Success; +} + +int +ProcRRQueryProviderProperty(ClientPtr client) +{ + REQUEST(xRRQueryProviderPropertyReq); + xRRQueryProviderPropertyReply rep; + RRProviderPtr provider; + RRPropertyPtr prop; + char *extra = NULL; + + REQUEST_SIZE_MATCH(xRRQueryProviderPropertyReq); + + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + prop = RRQueryProviderProperty(provider, 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) { + swaps(&rep.sequenceNumber); + swapl(&rep.length); + } + WriteToClient(client, sizeof(xRRQueryProviderPropertyReply), (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 +ProcRRConfigureProviderProperty(ClientPtr client) +{ + REQUEST(xRRConfigureProviderPropertyReq); + RRProviderPtr provider; + int num_valid; + + REQUEST_AT_LEAST_SIZE(xRRConfigureProviderPropertyReq); + + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + num_valid = + stuff->length - bytes_to_int32(sizeof(xRRConfigureProviderPropertyReq)); + return RRConfigureProviderProperty(provider, stuff->property, stuff->pending, + stuff->range, FALSE, num_valid, + (INT32 *) (stuff + 1)); +} + +int +ProcRRChangeProviderProperty(ClientPtr client) +{ + REQUEST(xRRChangeProviderPropertyReq); + RRProviderPtr provider; + char format, mode; + unsigned long len; + int sizeInBytes; + int totalSize; + int err; + + REQUEST_AT_LEAST_SIZE(xRRChangeProviderPropertyReq); + 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(xRRChangeProviderPropertyReq, totalSize); + + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + if (!ValidAtom(stuff->property)) { + client->errorValue = stuff->property; + return BadAtom; + } + if (!ValidAtom(stuff->type)) { + client->errorValue = stuff->type; + return BadAtom; + } + + err = RRChangeProviderProperty(provider, stuff->property, + stuff->type, (int) format, + (int) mode, len, (pointer) &stuff[1], TRUE, + TRUE); + if (err != Success) + return err; + else + return Success; +} + +int +ProcRRDeleteProviderProperty(ClientPtr client) +{ + REQUEST(xRRDeleteProviderPropertyReq); + RRProviderPtr provider; + RRPropertyPtr prop; + + REQUEST_SIZE_MATCH(xRRDeleteProviderPropertyReq); + UpdateCurrentTime(); + VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); + + if (!ValidAtom(stuff->property)) { + client->errorValue = stuff->property; + return BadAtom; + } + + prop = RRQueryProviderProperty(provider, stuff->property); + if (!prop) { + client->errorValue = stuff->property; + return BadName; + } + + if (prop->immutable) { + client->errorValue = stuff->property; + return BadAccess; + } + + RRDeleteProviderProperty(provider, stuff->property); + return Success; +} + +int +ProcRRGetProviderProperty(ClientPtr client) +{ + REQUEST(xRRGetProviderPropertyReq); + RRPropertyPtr prop, *prev; + RRPropertyValuePtr prop_value; + unsigned long n, len, ind; + RRProviderPtr provider; + xRRGetProviderPropertyReply reply; + char *extra = NULL; + + REQUEST_SIZE_MATCH(xRRGetProviderPropertyReq); + if (stuff->delete) + UpdateCurrentTime(); + VERIFY_RR_PROVIDER(stuff->provider, provider, + 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 = &provider->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) { + swaps(&reply.sequenceNumber); + swapl(&reply.length); + swapl(&reply.propertyType); + swapl(&reply.bytesAfter); + swapl(&reply.nItems); + } + WriteToClient(client, sizeof(xRRGetProviderPropertyReply), &reply); + return Success; + } + + if (prop->immutable && stuff->delete) + return BadAccess; + + prop_value = RRGetProviderProperty(provider, stuff->property, stuff->pending); + if (!prop_value) + return BadAtom; + + /* If the request type and actual type don't match. Return the + property information, but not the data. */ + + 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) { + swaps(&reply.sequenceNumber); + swapl(&reply.length); + swapl(&reply.propertyType); + swapl(&reply.bytesAfter); + swapl(&reply.nItems); + } + WriteToClient(client, sizeof(xRRGetProviderPropertyReply), &reply); + return Success; + } + +/* + * Return type, format, value to client + */ + n = (prop_value->format / 8) * prop_value->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); + + 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)) { + xRRProviderPropertyNotifyEvent event; + + event.type = RREventBase + RRNotify; + event.subCode = RRNotify_ProviderProperty; + event.provider = provider->id; + event.state = PropertyDelete; + event.atom = prop->propertyName; + event.timestamp = currentTime.milliseconds; + RRDeliverPropertyEvent(provider->pScreen, (xEvent *) &event); + } + + if (client->swapped) { + swaps(&reply.sequenceNumber); + swapl(&reply.length); + swapl(&reply.propertyType); + swapl(&reply.bytesAfter); + swapl(&reply.nItems); + } + 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)) { /* delete the Property */ + *prev = prop->next; + RRDestroyProviderProperty(prop); + } + return Success; +} -- cgit v1.2.3