[PATCH 11/36] randr: add provider object and provider property support (v6)

Dave Airlie airlied at gmail.com
Thu Jul 5 08:21:12 PDT 2012


From: Dave Airlie <airlied at redhat.com>

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
Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 hw/xfree86/common/xf86platformBus.c |    9 +-
 randr/Makefile.am                   |    2 +
 randr/randr.c                       |   57 ++-
 randr/randrstr.h                    |  103 ++++-
 randr/rrdispatch.c                  |   14 +-
 randr/rrprovider.c                  |  280 ++++++++++++++
 randr/rrproviderproperty.c          |  716 +++++++++++++++++++++++++++++++++++
 7 files changed, 1175 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 3bfb22e..24b9473 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 de338b9..ccaff3f 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 103da48..103c31e 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);
@@ -176,6 +179,47 @@ SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent * from,
 }
 
 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)
 {
     switch (from->u.u.detail) {
@@ -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 38fb107..0e04b74 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,17 @@ struct _rrOutput {
     void *devPrivate;
 };
 
+struct _rrProvider {
+    RRProvider id;
+    ScreenPtr pScreen; /* gpu screen more than likely */
+    uint32_t capabilities;
+    void *devPrivate;
+    char *name;
+    int nameLength;
+    RRPropertyPtr properties;
+    Bool pendingProperties;
+};
+
 #if RANDR_12_INTERFACE
 typedef Bool (*RRScreenSetSizeProcPtr) (ScreenPtr pScreen,
                                         CARD16 width,
@@ -197,6 +210,17 @@ typedef Bool (*RRSetPanningProcPtr) (ScreenPtr pScrn,
 
 #endif                          /* RANDR_13_INTERFACE */
 
+typedef Bool (*RRProviderSetRoleProcPtr)(ScreenPtr pScreen,
+                                         RRProviderPtr provider,
+                                         uint32_t new_role);
+
+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 +271,8 @@ typedef struct _rrScrPriv {
     RRSetPanningProcPtr rrSetPanning;
 #endif
 
+    RRProviderGetPropertyProcPtr rrProviderGetProperty;
+    RRProviderSetPropertyProcPtr rrProviderSetProperty;
     /*
      * Private part of the structure; not considered part of the ABI
      */
@@ -288,6 +314,8 @@ typedef struct _rrScrPriv {
     int size;
 #endif
     Bool discontiguous;
+
+    RRProviderPtr provider;
 } rrScrPrivRec, *rrScrPrivPtr;
 
 extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec;
@@ -331,7 +359,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 +391,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 +862,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, void *devPrivate);
+
+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 85cf037..054e47a 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 0000000..b787b94
--- /dev/null
+++ b/randr/rrprovider.c
@@ -0,0 +1,280 @@
+/*
+ * 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, void *devPrivate)
+{
+    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->devPrivate = devPrivate;
+    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 0000000..5e04fab
--- /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;
+}
-- 
1.7.10.2



More information about the xorg-devel mailing list