xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

rrproperty.c (22817B)


      1 /*
      2  * Copyright © 2006 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that copyright
      7  * notice and this permission notice appear in supporting documentation, and
      8  * that the name of the copyright holders not be used in advertising or
      9  * publicity pertaining to distribution of the software without specific,
     10  * written prior permission.  The copyright holders make no representations
     11  * about the suitability of this software for any purpose.  It is provided "as
     12  * is" without express or implied warranty.
     13  *
     14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     20  * OF THIS SOFTWARE.
     21  */
     22 
     23 #include "randrstr.h"
     24 #include "propertyst.h"
     25 #include "swaprep.h"
     26 #include <X11/Xatom.h>
     27 
     28 static int
     29 DeliverPropertyEvent(WindowPtr pWin, void *value)
     30 {
     31     xRROutputPropertyNotifyEvent *event = value;
     32     RREventPtr *pHead, pRREvent;
     33 
     34     dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
     35                             RREventType, serverClient, DixReadAccess);
     36     if (!pHead)
     37         return WT_WALKCHILDREN;
     38 
     39     for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
     40         if (!(pRREvent->mask & RROutputPropertyNotifyMask))
     41             continue;
     42 
     43         event->window = pRREvent->window->drawable.id;
     44         WriteEventsToClient(pRREvent->client, 1, (xEvent *) event);
     45     }
     46 
     47     return WT_WALKCHILDREN;
     48 }
     49 
     50 static void
     51 RRDeliverPropertyEvent(ScreenPtr pScreen, xEvent *event)
     52 {
     53     if (!(dispatchException & (DE_RESET | DE_TERMINATE)))
     54         WalkTree(pScreen, DeliverPropertyEvent, event);
     55 }
     56 
     57 static void
     58 RRDestroyOutputProperty(RRPropertyPtr prop)
     59 {
     60     free(prop->valid_values);
     61     free(prop->current.data);
     62     free(prop->pending.data);
     63     free(prop);
     64 }
     65 
     66 static void
     67 RRDeleteProperty(RROutputRec * output, RRPropertyRec * prop)
     68 {
     69     xRROutputPropertyNotifyEvent event = {
     70         .type = RREventBase + RRNotify,
     71         .subCode = RRNotify_OutputProperty,
     72         .output = output->id,
     73         .state = PropertyDelete,
     74         .atom = prop->propertyName,
     75         .timestamp = currentTime.milliseconds
     76     };
     77 
     78     RRDeliverPropertyEvent(output->pScreen, (xEvent *) &event);
     79 
     80     RRDestroyOutputProperty(prop);
     81 }
     82 
     83 void
     84 RRDeleteAllOutputProperties(RROutputPtr output)
     85 {
     86     RRPropertyPtr prop, next;
     87 
     88     for (prop = output->properties; prop; prop = next) {
     89         next = prop->next;
     90         RRDeleteProperty(output, prop);
     91     }
     92 }
     93 
     94 static void
     95 RRInitOutputPropertyValue(RRPropertyValuePtr property_value)
     96 {
     97     property_value->type = None;
     98     property_value->format = 0;
     99     property_value->size = 0;
    100     property_value->data = NULL;
    101 }
    102 
    103 static RRPropertyPtr
    104 RRCreateOutputProperty(Atom property)
    105 {
    106     RRPropertyPtr prop;
    107 
    108     prop = (RRPropertyPtr) malloc(sizeof(RRPropertyRec));
    109     if (!prop)
    110         return NULL;
    111     prop->next = NULL;
    112     prop->propertyName = property;
    113     prop->is_pending = FALSE;
    114     prop->range = FALSE;
    115     prop->immutable = FALSE;
    116     prop->num_valid = 0;
    117     prop->valid_values = NULL;
    118     RRInitOutputPropertyValue(&prop->current);
    119     RRInitOutputPropertyValue(&prop->pending);
    120     return prop;
    121 }
    122 
    123 void
    124 RRDeleteOutputProperty(RROutputPtr output, Atom property)
    125 {
    126     RRPropertyRec *prop, **prev;
    127 
    128     for (prev = &output->properties; (prop = *prev); prev = &(prop->next))
    129         if (prop->propertyName == property) {
    130             *prev = prop->next;
    131             RRDeleteProperty(output, prop);
    132             return;
    133         }
    134 }
    135 
    136 static void
    137 RRNoticePropertyChange(RROutputPtr output, Atom property, RRPropertyValuePtr value)
    138 {
    139     const char *non_desktop_str = RR_PROPERTY_NON_DESKTOP;
    140     Atom non_desktop_prop = MakeAtom(non_desktop_str, strlen(non_desktop_str), FALSE);
    141 
    142     if (property == non_desktop_prop) {
    143         if (value->type == XA_INTEGER && value->format == 32 && value->size >= 1) {
    144             uint32_t     nonDesktopData;
    145             Bool        nonDesktop;
    146 
    147             memcpy(&nonDesktopData, value->data, sizeof (nonDesktopData));
    148             nonDesktop = nonDesktopData != 0;
    149 
    150             if (nonDesktop != output->nonDesktop) {
    151                 output->nonDesktop = nonDesktop;
    152                 RROutputChanged(output, 0);
    153                 RRTellChanged(output->pScreen);
    154             }
    155         }
    156     }
    157 }
    158 
    159 int
    160 RRChangeOutputProperty(RROutputPtr output, Atom property, Atom type,
    161                        int format, int mode, unsigned long len,
    162                        const void *value, Bool sendevent, Bool pending)
    163 {
    164     RRPropertyPtr prop;
    165     rrScrPrivPtr pScrPriv = rrGetScrPriv(output->pScreen);
    166     int size_in_bytes;
    167     unsigned long total_len;
    168     RRPropertyValuePtr prop_value;
    169     RRPropertyValueRec new_value;
    170     Bool add = FALSE;
    171 
    172     size_in_bytes = format >> 3;
    173 
    174     /* first see if property already exists */
    175     prop = RRQueryOutputProperty(output, property);
    176     if (!prop) {                /* just add to list */
    177         prop = RRCreateOutputProperty(property);
    178         if (!prop)
    179             return BadAlloc;
    180         add = TRUE;
    181         mode = PropModeReplace;
    182     }
    183     if (pending && prop->is_pending)
    184         prop_value = &prop->pending;
    185     else
    186         prop_value = &prop->current;
    187 
    188     /* To append or prepend to a property the request format and type
    189        must match those of the already defined property.  The
    190        existing format and type are irrelevant when using the mode
    191        "PropModeReplace" since they will be written over. */
    192 
    193     if ((format != prop_value->format) && (mode != PropModeReplace))
    194         return BadMatch;
    195     if ((prop_value->type != type) && (mode != PropModeReplace))
    196         return BadMatch;
    197     new_value = *prop_value;
    198     if (mode == PropModeReplace)
    199         total_len = len;
    200     else
    201         total_len = prop_value->size + len;
    202 
    203     if (mode == PropModeReplace || len > 0) {
    204         void *new_data = NULL, *old_data = NULL;
    205 
    206         new_value.data = xallocarray(total_len, size_in_bytes);
    207         if (!new_value.data && total_len && size_in_bytes) {
    208             if (add)
    209                 RRDestroyOutputProperty(prop);
    210             return BadAlloc;
    211         }
    212         new_value.size = len;
    213         new_value.type = type;
    214         new_value.format = format;
    215 
    216         switch (mode) {
    217         case PropModeReplace:
    218             new_data = new_value.data;
    219             old_data = NULL;
    220             break;
    221         case PropModeAppend:
    222             new_data = (void *) (((char *) new_value.data) +
    223                                   (prop_value->size * size_in_bytes));
    224             old_data = new_value.data;
    225             break;
    226         case PropModePrepend:
    227             new_data = new_value.data;
    228             old_data = (void *) (((char *) new_value.data) +
    229                                   (prop_value->size * size_in_bytes));
    230             break;
    231         }
    232         if (new_data)
    233             memcpy((char *) new_data, (char *) value, len * size_in_bytes);
    234         if (old_data)
    235             memcpy((char *) old_data, (char *) prop_value->data,
    236                    prop_value->size * size_in_bytes);
    237 
    238         if (pending && pScrPriv->rrOutputSetProperty &&
    239             !pScrPriv->rrOutputSetProperty(output->pScreen, output,
    240                                            prop->propertyName, &new_value)) {
    241             free(new_value.data);
    242             if (add)
    243                 RRDestroyOutputProperty(prop);
    244             return BadValue;
    245         }
    246         free(prop_value->data);
    247         *prop_value = new_value;
    248     }
    249 
    250     else if (len == 0) {
    251         /* do nothing */
    252     }
    253 
    254     if (add) {
    255         prop->next = output->properties;
    256         output->properties = prop;
    257     }
    258 
    259     if (pending && prop->is_pending)
    260         output->pendingProperties = TRUE;
    261 
    262     if (!(pending && prop->is_pending))
    263         RRNoticePropertyChange(output, prop->propertyName, prop_value);
    264 
    265     if (sendevent) {
    266         xRROutputPropertyNotifyEvent event = {
    267             .type = RREventBase + RRNotify,
    268             .subCode = RRNotify_OutputProperty,
    269             .output = output->id,
    270             .state = PropertyNewValue,
    271             .atom = prop->propertyName,
    272             .timestamp = currentTime.milliseconds
    273         };
    274         RRDeliverPropertyEvent(output->pScreen, (xEvent *) &event);
    275     }
    276     return Success;
    277 }
    278 
    279 Bool
    280 RRPostPendingProperties(RROutputPtr output)
    281 {
    282     RRPropertyValuePtr pending_value;
    283     RRPropertyValuePtr current_value;
    284     RRPropertyPtr property;
    285     Bool ret = TRUE;
    286 
    287     if (!output->pendingProperties)
    288         return TRUE;
    289 
    290     output->pendingProperties = FALSE;
    291     for (property = output->properties; property; property = property->next) {
    292         /* Skip non-pending properties */
    293         if (!property->is_pending)
    294             continue;
    295 
    296         pending_value = &property->pending;
    297         current_value = &property->current;
    298 
    299         /*
    300          * If the pending and current values are equal, don't mark it
    301          * as changed (which would deliver an event)
    302          */
    303         if (pending_value->type == current_value->type &&
    304             pending_value->format == current_value->format &&
    305             pending_value->size == current_value->size &&
    306             !memcmp(pending_value->data, current_value->data,
    307                     pending_value->size * (pending_value->format / 8)))
    308             continue;
    309 
    310         if (RRChangeOutputProperty(output, property->propertyName,
    311                                    pending_value->type, pending_value->format,
    312                                    PropModeReplace, pending_value->size,
    313                                    pending_value->data, TRUE, FALSE) != Success)
    314             ret = FALSE;
    315     }
    316     return ret;
    317 }
    318 
    319 RRPropertyPtr
    320 RRQueryOutputProperty(RROutputPtr output, Atom property)
    321 {
    322     RRPropertyPtr prop;
    323 
    324     for (prop = output->properties; prop; prop = prop->next)
    325         if (prop->propertyName == property)
    326             return prop;
    327     return NULL;
    328 }
    329 
    330 RRPropertyValuePtr
    331 RRGetOutputProperty(RROutputPtr output, Atom property, Bool pending)
    332 {
    333     RRPropertyPtr prop = RRQueryOutputProperty(output, property);
    334     rrScrPrivPtr pScrPriv = rrGetScrPriv(output->pScreen);
    335 
    336     if (!prop)
    337         return NULL;
    338     if (pending && prop->is_pending)
    339         return &prop->pending;
    340     else {
    341 #if RANDR_13_INTERFACE
    342         /* If we can, try to update the property value first */
    343         if (pScrPriv->rrOutputGetProperty)
    344             pScrPriv->rrOutputGetProperty(output->pScreen, output,
    345                                           prop->propertyName);
    346 #endif
    347         return &prop->current;
    348     }
    349 }
    350 
    351 int
    352 RRConfigureOutputProperty(RROutputPtr output, Atom property,
    353                           Bool pending, Bool range, Bool immutable,
    354                           int num_values, const INT32 *values)
    355 {
    356     RRPropertyPtr prop = RRQueryOutputProperty(output, property);
    357     Bool add = FALSE;
    358     INT32 *new_values;
    359 
    360     if (!prop) {
    361         prop = RRCreateOutputProperty(property);
    362         if (!prop)
    363             return BadAlloc;
    364         add = TRUE;
    365     }
    366     else if (prop->immutable && !immutable)
    367         return BadAccess;
    368 
    369     /*
    370      * ranges must have even number of values
    371      */
    372     if (range && (num_values & 1)) {
    373         if (add)
    374             RRDestroyOutputProperty(prop);
    375         return BadMatch;
    376     }
    377 
    378     new_values = xallocarray(num_values, sizeof(INT32));
    379     if (!new_values && num_values) {
    380         if (add)
    381             RRDestroyOutputProperty(prop);
    382         return BadAlloc;
    383     }
    384     if (num_values)
    385         memcpy(new_values, values, num_values * sizeof(INT32));
    386 
    387     /*
    388      * Property moving from pending to non-pending
    389      * loses any pending values
    390      */
    391     if (prop->is_pending && !pending) {
    392         free(prop->pending.data);
    393         RRInitOutputPropertyValue(&prop->pending);
    394     }
    395 
    396     prop->is_pending = pending;
    397     prop->range = range;
    398     prop->immutable = immutable;
    399     prop->num_valid = num_values;
    400     free(prop->valid_values);
    401     prop->valid_values = new_values;
    402 
    403     if (add) {
    404         prop->next = output->properties;
    405         output->properties = prop;
    406     }
    407 
    408     return Success;
    409 }
    410 
    411 int
    412 ProcRRListOutputProperties(ClientPtr client)
    413 {
    414     REQUEST(xRRListOutputPropertiesReq);
    415     Atom *pAtoms = NULL;
    416     xRRListOutputPropertiesReply rep;
    417     int numProps = 0;
    418     RROutputPtr output;
    419     RRPropertyPtr prop;
    420 
    421     REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq);
    422 
    423     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
    424 
    425     for (prop = output->properties; prop; prop = prop->next)
    426         numProps++;
    427     if (numProps)
    428         if (!(pAtoms = xallocarray(numProps, sizeof(Atom))))
    429             return BadAlloc;
    430 
    431     rep = (xRRListOutputPropertiesReply) {
    432         .type = X_Reply,
    433         .sequenceNumber = client->sequence,
    434         .length = bytes_to_int32(numProps * sizeof(Atom)),
    435         .nAtoms = numProps
    436     };
    437     if (client->swapped) {
    438         swaps(&rep.sequenceNumber);
    439         swapl(&rep.length);
    440         swaps(&rep.nAtoms);
    441     }
    442     WriteToClient(client, sizeof(xRRListOutputPropertiesReply), &rep);
    443 
    444     if (numProps) {
    445         /* Copy property name atoms to reply buffer */
    446         Atom *temppAtoms = pAtoms;
    447         for (prop = output->properties; prop; prop = prop->next)
    448             *temppAtoms++ = prop->propertyName;
    449 
    450         client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
    451         WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
    452         free(pAtoms);
    453     }
    454     return Success;
    455 }
    456 
    457 int
    458 ProcRRQueryOutputProperty(ClientPtr client)
    459 {
    460     REQUEST(xRRQueryOutputPropertyReq);
    461     xRRQueryOutputPropertyReply rep;
    462     RROutputPtr output;
    463     RRPropertyPtr prop;
    464     char *extra = NULL;
    465 
    466     REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq);
    467 
    468     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
    469 
    470     prop = RRQueryOutputProperty(output, stuff->property);
    471     if (!prop)
    472         return BadName;
    473 
    474     if (prop->num_valid) {
    475         extra = xallocarray(prop->num_valid, sizeof(INT32));
    476         if (!extra)
    477             return BadAlloc;
    478     }
    479 
    480     rep = (xRRQueryOutputPropertyReply) {
    481         .type = X_Reply,
    482         .sequenceNumber = client->sequence,
    483         .length = prop->num_valid,
    484         .pending = prop->is_pending,
    485         .range = prop->range,
    486         .immutable = prop->immutable
    487     };
    488 
    489     if (client->swapped) {
    490         swaps(&rep.sequenceNumber);
    491         swapl(&rep.length);
    492     }
    493     WriteToClient(client, sizeof(xRRQueryOutputPropertyReply), &rep);
    494     if (prop->num_valid) {
    495         memcpy(extra, prop->valid_values, prop->num_valid * sizeof(INT32));
    496         client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
    497         WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32),
    498                                  extra);
    499         free(extra);
    500     }
    501     return Success;
    502 }
    503 
    504 int
    505 ProcRRConfigureOutputProperty(ClientPtr client)
    506 {
    507     REQUEST(xRRConfigureOutputPropertyReq);
    508     RROutputPtr output;
    509     int num_valid;
    510 
    511     REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq);
    512 
    513     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
    514 
    515     if (RROutputIsLeased(output))
    516         return BadAccess;
    517 
    518     num_valid =
    519         stuff->length - bytes_to_int32(sizeof(xRRConfigureOutputPropertyReq));
    520     return RRConfigureOutputProperty(output, stuff->property, stuff->pending,
    521                                      stuff->range, FALSE, num_valid,
    522                                      (INT32 *) (stuff + 1));
    523 }
    524 
    525 int
    526 ProcRRChangeOutputProperty(ClientPtr client)
    527 {
    528     REQUEST(xRRChangeOutputPropertyReq);
    529     RROutputPtr output;
    530     char format, mode;
    531     unsigned long len;
    532     int sizeInBytes;
    533     int totalSize;
    534     int err;
    535 
    536     REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq);
    537     UpdateCurrentTime();
    538     format = stuff->format;
    539     mode = stuff->mode;
    540     if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
    541         (mode != PropModePrepend)) {
    542         client->errorValue = mode;
    543         return BadValue;
    544     }
    545     if ((format != 8) && (format != 16) && (format != 32)) {
    546         client->errorValue = format;
    547         return BadValue;
    548     }
    549     len = stuff->nUnits;
    550     if (len > bytes_to_int32((0xffffffff - sizeof(xChangePropertyReq))))
    551         return BadLength;
    552     sizeInBytes = format >> 3;
    553     totalSize = len * sizeInBytes;
    554     REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq, totalSize);
    555 
    556     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
    557 
    558     if (!ValidAtom(stuff->property)) {
    559         client->errorValue = stuff->property;
    560         return BadAtom;
    561     }
    562     if (!ValidAtom(stuff->type)) {
    563         client->errorValue = stuff->type;
    564         return BadAtom;
    565     }
    566 
    567     err = RRChangeOutputProperty(output, stuff->property,
    568                                  stuff->type, (int) format,
    569                                  (int) mode, len, (void *) &stuff[1], TRUE,
    570                                  TRUE);
    571     if (err != Success)
    572         return err;
    573     else
    574         return Success;
    575 }
    576 
    577 int
    578 ProcRRDeleteOutputProperty(ClientPtr client)
    579 {
    580     REQUEST(xRRDeleteOutputPropertyReq);
    581     RROutputPtr output;
    582     RRPropertyPtr prop;
    583 
    584     REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq);
    585     UpdateCurrentTime();
    586     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
    587 
    588     if (RROutputIsLeased(output))
    589         return BadAccess;
    590 
    591     if (!ValidAtom(stuff->property)) {
    592         client->errorValue = stuff->property;
    593         return BadAtom;
    594     }
    595 
    596     prop = RRQueryOutputProperty(output, stuff->property);
    597     if (!prop) {
    598         client->errorValue = stuff->property;
    599         return BadName;
    600     }
    601 
    602     if (prop->immutable) {
    603         client->errorValue = stuff->property;
    604         return BadAccess;
    605     }
    606 
    607     RRDeleteOutputProperty(output, stuff->property);
    608     return Success;
    609 }
    610 
    611 int
    612 ProcRRGetOutputProperty(ClientPtr client)
    613 {
    614     REQUEST(xRRGetOutputPropertyReq);
    615     RRPropertyPtr prop, *prev;
    616     RRPropertyValuePtr prop_value;
    617     unsigned long n, len, ind;
    618     RROutputPtr output;
    619     xRRGetOutputPropertyReply reply;
    620     char *extra = NULL;
    621 
    622     REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq);
    623     if (stuff->delete)
    624         UpdateCurrentTime();
    625     VERIFY_RR_OUTPUT(stuff->output, output,
    626                      stuff->delete ? DixWriteAccess : DixReadAccess);
    627 
    628     if (!ValidAtom(stuff->property)) {
    629         client->errorValue = stuff->property;
    630         return BadAtom;
    631     }
    632     if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) {
    633         client->errorValue = stuff->delete;
    634         return BadValue;
    635     }
    636     if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) {
    637         client->errorValue = stuff->type;
    638         return BadAtom;
    639     }
    640 
    641     for (prev = &output->properties; (prop = *prev); prev = &prop->next)
    642         if (prop->propertyName == stuff->property)
    643             break;
    644 
    645     reply = (xRRGetOutputPropertyReply) {
    646         .type = X_Reply,
    647         .sequenceNumber = client->sequence
    648     };
    649     if (!prop) {
    650         reply.nItems = 0;
    651         reply.length = 0;
    652         reply.bytesAfter = 0;
    653         reply.propertyType = None;
    654         reply.format = 0;
    655         if (client->swapped) {
    656             swaps(&reply.sequenceNumber);
    657             swapl(&reply.length);
    658             swapl(&reply.propertyType);
    659             swapl(&reply.bytesAfter);
    660             swapl(&reply.nItems);
    661         }
    662         WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
    663         return Success;
    664     }
    665 
    666     if (prop->immutable && stuff->delete)
    667         return BadAccess;
    668 
    669     prop_value = RRGetOutputProperty(output, stuff->property, stuff->pending);
    670     if (!prop_value)
    671         return BadAtom;
    672 
    673     /* If the request type and actual type don't match. Return the
    674        property information, but not the data. */
    675 
    676     if (((stuff->type != prop_value->type) && (stuff->type != AnyPropertyType))
    677         ) {
    678         reply.bytesAfter = prop_value->size;
    679         reply.format = prop_value->format;
    680         reply.length = 0;
    681         reply.nItems = 0;
    682         reply.propertyType = prop_value->type;
    683         if (client->swapped) {
    684             swaps(&reply.sequenceNumber);
    685             swapl(&reply.length);
    686             swapl(&reply.propertyType);
    687             swapl(&reply.bytesAfter);
    688             swapl(&reply.nItems);
    689         }
    690         WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
    691         return Success;
    692     }
    693 
    694 /*
    695  *  Return type, format, value to client
    696  */
    697     n = (prop_value->format / 8) * prop_value->size;    /* size (bytes) of prop */
    698     ind = stuff->longOffset << 2;
    699 
    700     /* If longOffset is invalid such that it causes "len" to
    701        be negative, it's a value error. */
    702 
    703     if (n < ind) {
    704         client->errorValue = stuff->longOffset;
    705         return BadValue;
    706     }
    707 
    708     len = min(n - ind, 4 * stuff->longLength);
    709 
    710     if (len) {
    711         extra = malloc(len);
    712         if (!extra)
    713             return BadAlloc;
    714     }
    715     reply.bytesAfter = n - (ind + len);
    716     reply.format = prop_value->format;
    717     reply.length = bytes_to_int32(len);
    718     if (prop_value->format)
    719         reply.nItems = len / (prop_value->format / 8);
    720     else
    721         reply.nItems = 0;
    722     reply.propertyType = prop_value->type;
    723 
    724     if (stuff->delete && (reply.bytesAfter == 0)) {
    725         xRROutputPropertyNotifyEvent event = {
    726             .type = RREventBase + RRNotify,
    727             .subCode = RRNotify_OutputProperty,
    728             .output = output->id,
    729             .state = PropertyDelete,
    730             .atom = prop->propertyName,
    731             .timestamp = currentTime.milliseconds
    732         };
    733         RRDeliverPropertyEvent(output->pScreen, (xEvent *) &event);
    734     }
    735 
    736     if (client->swapped) {
    737         swaps(&reply.sequenceNumber);
    738         swapl(&reply.length);
    739         swapl(&reply.propertyType);
    740         swapl(&reply.bytesAfter);
    741         swapl(&reply.nItems);
    742     }
    743     WriteToClient(client, sizeof(xGenericReply), &reply);
    744     if (len) {
    745         memcpy(extra, (char *) prop_value->data + ind, len);
    746         switch (reply.format) {
    747         case 32:
    748             client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write;
    749             break;
    750         case 16:
    751             client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write;
    752             break;
    753         default:
    754             client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient;
    755             break;
    756         }
    757         WriteSwappedDataToClient(client, len, extra);
    758         free(extra);
    759     }
    760 
    761     if (stuff->delete && (reply.bytesAfter == 0)) {     /* delete the Property */
    762         *prev = prop->next;
    763         RRDestroyOutputProperty(prop);
    764     }
    765     return Success;
    766 }