xserver

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

rroutput.c (19369B)


      1 /*
      2  * Copyright © 2006 Keith Packard
      3  * Copyright © 2008 Red Hat, Inc.
      4  *
      5  * Permission to use, copy, modify, distribute, and sell this software and its
      6  * documentation for any purpose is hereby granted without fee, provided that
      7  * the above copyright notice appear in all copies and that both that copyright
      8  * notice and this permission notice appear in supporting documentation, and
      9  * that the name of the copyright holders not be used in advertising or
     10  * publicity pertaining to distribution of the software without specific,
     11  * written prior permission.  The copyright holders make no representations
     12  * about the suitability of this software for any purpose.  It is provided "as
     13  * is" without express or implied warranty.
     14  *
     15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     17  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     21  * OF THIS SOFTWARE.
     22  */
     23 
     24 #include "randrstr.h"
     25 #include <X11/Xatom.h>
     26 
     27 RESTYPE RROutputType;
     28 
     29 /*
     30  * Notify the output of some change
     31  */
     32 void
     33 RROutputChanged(RROutputPtr output, Bool configChanged)
     34 {
     35     /* set changed bits on the primary screen only */
     36     ScreenPtr pScreen = output->pScreen;
     37     rrScrPrivPtr primarysp;
     38 
     39     output->changed = TRUE;
     40     if (!pScreen)
     41         return;
     42 
     43     if (pScreen->isGPU) {
     44         ScreenPtr primary = pScreen->current_primary;
     45         if (!primary)
     46             return;
     47         primarysp = rrGetScrPriv(primary);
     48     }
     49     else {
     50         primarysp = rrGetScrPriv(pScreen);
     51     }
     52 
     53     RRSetChanged(pScreen);
     54     if (configChanged)
     55         primarysp->configChanged = TRUE;
     56 }
     57 
     58 /*
     59  * Create an output
     60  */
     61 
     62 RROutputPtr
     63 RROutputCreate(ScreenPtr pScreen,
     64                const char *name, int nameLength, void *devPrivate)
     65 {
     66     RROutputPtr output;
     67     RROutputPtr *outputs;
     68     rrScrPrivPtr pScrPriv;
     69     Atom nonDesktopAtom;
     70 
     71     if (!RRInit())
     72         return NULL;
     73 
     74     pScrPriv = rrGetScrPriv(pScreen);
     75 
     76     outputs = reallocarray(pScrPriv->outputs,
     77                            pScrPriv->numOutputs + 1, sizeof(RROutputPtr));
     78     if (!outputs)
     79         return NULL;
     80 
     81     pScrPriv->outputs = outputs;
     82 
     83     output = malloc(sizeof(RROutputRec) + nameLength + 1);
     84     if (!output)
     85         return NULL;
     86     output->id = FakeClientID(0);
     87     output->pScreen = pScreen;
     88     output->name = (char *) (output + 1);
     89     output->nameLength = nameLength;
     90     memcpy(output->name, name, nameLength);
     91     output->name[nameLength] = '\0';
     92     output->connection = RR_UnknownConnection;
     93     output->subpixelOrder = SubPixelUnknown;
     94     output->mmWidth = 0;
     95     output->mmHeight = 0;
     96     output->crtc = NULL;
     97     output->numCrtcs = 0;
     98     output->crtcs = NULL;
     99     output->numClones = 0;
    100     output->clones = NULL;
    101     output->numModes = 0;
    102     output->numPreferred = 0;
    103     output->modes = NULL;
    104     output->numUserModes = 0;
    105     output->userModes = NULL;
    106     output->properties = NULL;
    107     output->pendingProperties = FALSE;
    108     output->changed = FALSE;
    109     output->nonDesktop = FALSE;
    110     output->devPrivate = devPrivate;
    111 
    112     if (!AddResource(output->id, RROutputType, (void *) output))
    113         return NULL;
    114 
    115     pScrPriv->outputs[pScrPriv->numOutputs++] = output;
    116 
    117     nonDesktopAtom = MakeAtom(RR_PROPERTY_NON_DESKTOP, strlen(RR_PROPERTY_NON_DESKTOP), TRUE);
    118     if (nonDesktopAtom != BAD_RESOURCE) {
    119         static const INT32 values[2] = { 0, 1 };
    120         (void) RRConfigureOutputProperty(output, nonDesktopAtom, FALSE, FALSE, FALSE,
    121                                             2, values);
    122     }
    123     RROutputSetNonDesktop(output, FALSE);
    124     RRResourcesChanged(pScreen);
    125 
    126     return output;
    127 }
    128 
    129 /*
    130  * Notify extension that output parameters have been changed
    131  */
    132 Bool
    133 RROutputSetClones(RROutputPtr output, RROutputPtr * clones, int numClones)
    134 {
    135     RROutputPtr *newClones;
    136     int i;
    137 
    138     if (numClones == output->numClones) {
    139         for (i = 0; i < numClones; i++)
    140             if (output->clones[i] != clones[i])
    141                 break;
    142         if (i == numClones)
    143             return TRUE;
    144     }
    145     if (numClones) {
    146         newClones = xallocarray(numClones, sizeof(RROutputPtr));
    147         if (!newClones)
    148             return FALSE;
    149     }
    150     else
    151         newClones = NULL;
    152     free(output->clones);
    153     memcpy(newClones, clones, numClones * sizeof(RROutputPtr));
    154     output->clones = newClones;
    155     output->numClones = numClones;
    156     RROutputChanged(output, TRUE);
    157     return TRUE;
    158 }
    159 
    160 Bool
    161 RROutputSetModes(RROutputPtr output,
    162                  RRModePtr * modes, int numModes, int numPreferred)
    163 {
    164     RRModePtr *newModes;
    165     int i;
    166 
    167     if (numModes == output->numModes && numPreferred == output->numPreferred) {
    168         for (i = 0; i < numModes; i++)
    169             if (output->modes[i] != modes[i])
    170                 break;
    171         if (i == numModes) {
    172             for (i = 0; i < numModes; i++)
    173                 RRModeDestroy(modes[i]);
    174             return TRUE;
    175         }
    176     }
    177 
    178     if (numModes) {
    179         newModes = xallocarray(numModes, sizeof(RRModePtr));
    180         if (!newModes)
    181             return FALSE;
    182     }
    183     else
    184         newModes = NULL;
    185     if (output->modes) {
    186         for (i = 0; i < output->numModes; i++)
    187             RRModeDestroy(output->modes[i]);
    188         free(output->modes);
    189     }
    190     memcpy(newModes, modes, numModes * sizeof(RRModePtr));
    191     output->modes = newModes;
    192     output->numModes = numModes;
    193     output->numPreferred = numPreferred;
    194     RROutputChanged(output, TRUE);
    195     return TRUE;
    196 }
    197 
    198 int
    199 RROutputAddUserMode(RROutputPtr output, RRModePtr mode)
    200 {
    201     int m;
    202     ScreenPtr pScreen = output->pScreen;
    203 
    204     rrScrPriv(pScreen);
    205     RRModePtr *newModes;
    206 
    207     /* Check to see if this mode is already listed for this output */
    208     for (m = 0; m < output->numModes + output->numUserModes; m++) {
    209         RRModePtr e = (m < output->numModes ?
    210                        output->modes[m] :
    211                        output->userModes[m - output->numModes]);
    212         if (mode == e)
    213             return Success;
    214     }
    215 
    216     /* Check with the DDX to see if this mode is OK */
    217     if (pScrPriv->rrOutputValidateMode)
    218         if (!pScrPriv->rrOutputValidateMode(pScreen, output, mode))
    219             return BadMatch;
    220 
    221     if (output->userModes)
    222         newModes = reallocarray(output->userModes,
    223                                 output->numUserModes + 1, sizeof(RRModePtr));
    224     else
    225         newModes = malloc(sizeof(RRModePtr));
    226     if (!newModes)
    227         return BadAlloc;
    228 
    229     output->userModes = newModes;
    230     output->userModes[output->numUserModes++] = mode;
    231     ++mode->refcnt;
    232     RROutputChanged(output, TRUE);
    233     RRTellChanged(pScreen);
    234     return Success;
    235 }
    236 
    237 int
    238 RROutputDeleteUserMode(RROutputPtr output, RRModePtr mode)
    239 {
    240     int m;
    241 
    242     /* Find this mode in the user mode list */
    243     for (m = 0; m < output->numUserModes; m++) {
    244         RRModePtr e = output->userModes[m];
    245 
    246         if (mode == e)
    247             break;
    248     }
    249     /* Not there, access error */
    250     if (m == output->numUserModes)
    251         return BadAccess;
    252 
    253     /* make sure the mode isn't active for this output */
    254     if (output->crtc && output->crtc->mode == mode)
    255         return BadMatch;
    256 
    257     memmove(output->userModes + m, output->userModes + m + 1,
    258             (output->numUserModes - m - 1) * sizeof(RRModePtr));
    259     output->numUserModes--;
    260     RRModeDestroy(mode);
    261     return Success;
    262 }
    263 
    264 Bool
    265 RROutputSetCrtcs(RROutputPtr output, RRCrtcPtr * crtcs, int numCrtcs)
    266 {
    267     RRCrtcPtr *newCrtcs;
    268     int i;
    269 
    270     if (numCrtcs == output->numCrtcs) {
    271         for (i = 0; i < numCrtcs; i++)
    272             if (output->crtcs[i] != crtcs[i])
    273                 break;
    274         if (i == numCrtcs)
    275             return TRUE;
    276     }
    277     if (numCrtcs) {
    278         newCrtcs = xallocarray(numCrtcs, sizeof(RRCrtcPtr));
    279         if (!newCrtcs)
    280             return FALSE;
    281     }
    282     else
    283         newCrtcs = NULL;
    284     free(output->crtcs);
    285     memcpy(newCrtcs, crtcs, numCrtcs * sizeof(RRCrtcPtr));
    286     output->crtcs = newCrtcs;
    287     output->numCrtcs = numCrtcs;
    288     RROutputChanged(output, TRUE);
    289     return TRUE;
    290 }
    291 
    292 Bool
    293 RROutputSetConnection(RROutputPtr output, CARD8 connection)
    294 {
    295     if (output->connection == connection)
    296         return TRUE;
    297     output->connection = connection;
    298     RROutputChanged(output, TRUE);
    299     return TRUE;
    300 }
    301 
    302 Bool
    303 RROutputSetSubpixelOrder(RROutputPtr output, int subpixelOrder)
    304 {
    305     if (output->subpixelOrder == subpixelOrder)
    306         return TRUE;
    307 
    308     output->subpixelOrder = subpixelOrder;
    309     RROutputChanged(output, FALSE);
    310     return TRUE;
    311 }
    312 
    313 Bool
    314 RROutputSetPhysicalSize(RROutputPtr output, int mmWidth, int mmHeight)
    315 {
    316     if (output->mmWidth == mmWidth && output->mmHeight == mmHeight)
    317         return TRUE;
    318     output->mmWidth = mmWidth;
    319     output->mmHeight = mmHeight;
    320     RROutputChanged(output, FALSE);
    321     return TRUE;
    322 }
    323 
    324 Bool
    325 RROutputSetNonDesktop(RROutputPtr output, Bool nonDesktop)
    326 {
    327     const char *nonDesktopStr = RR_PROPERTY_NON_DESKTOP;
    328     Atom nonDesktopProp = MakeAtom(nonDesktopStr, strlen(nonDesktopStr), TRUE);
    329     uint32_t value = nonDesktop ? 1 : 0;
    330 
    331     if (nonDesktopProp == None || nonDesktopProp == BAD_RESOURCE)
    332         return FALSE;
    333 
    334     return RRChangeOutputProperty(output, nonDesktopProp, XA_INTEGER, 32,
    335                                   PropModeReplace, 1, &value, TRUE, FALSE) == Success;
    336 }
    337 
    338 void
    339 RRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output)
    340 {
    341     ScreenPtr pScreen = pWin->drawable.pScreen;
    342 
    343     rrScrPriv(pScreen);
    344     RRCrtcPtr crtc = output->crtc;
    345     RRModePtr mode = crtc ? crtc->mode : NULL;
    346 
    347     xRROutputChangeNotifyEvent oe = {
    348         .type = RRNotify + RREventBase,
    349         .subCode = RRNotify_OutputChange,
    350         .timestamp = pScrPriv->lastSetTime.milliseconds,
    351         .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
    352         .window = pWin->drawable.id,
    353         .output = output->id,
    354         .crtc = crtc ? crtc->id : None,
    355         .mode = mode ? mode->mode.id : None,
    356         .rotation = crtc ? crtc->rotation : RR_Rotate_0,
    357         .connection = output->nonDesktop ? RR_Disconnected : output->connection,
    358         .subpixelOrder = output->subpixelOrder
    359     };
    360     WriteEventsToClient(client, 1, (xEvent *) &oe);
    361 }
    362 
    363 /*
    364  * Destroy a Output at shutdown
    365  */
    366 void
    367 RROutputDestroy(RROutputPtr output)
    368 {
    369     FreeResource(output->id, 0);
    370 }
    371 
    372 static int
    373 RROutputDestroyResource(void *value, XID pid)
    374 {
    375     RROutputPtr output = (RROutputPtr) value;
    376     ScreenPtr pScreen = output->pScreen;
    377     int m;
    378 
    379     if (pScreen) {
    380         rrScrPriv(pScreen);
    381         int i;
    382         RRLeasePtr lease, next;
    383 
    384         xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) {
    385             int o;
    386             for (o = 0; o < lease->numOutputs; o++) {
    387                 if (lease->outputs[o] == output) {
    388                     RRTerminateLease(lease);
    389                     break;
    390                 }
    391             }
    392         }
    393 
    394         if (pScrPriv->primaryOutput == output)
    395             pScrPriv->primaryOutput = NULL;
    396 
    397         for (i = 0; i < pScrPriv->numOutputs; i++) {
    398             if (pScrPriv->outputs[i] == output) {
    399                 memmove(pScrPriv->outputs + i, pScrPriv->outputs + i + 1,
    400                         (pScrPriv->numOutputs - (i + 1)) * sizeof(RROutputPtr));
    401                 --pScrPriv->numOutputs;
    402                 break;
    403             }
    404         }
    405 
    406         RRResourcesChanged(pScreen);
    407     }
    408     if (output->modes) {
    409         for (m = 0; m < output->numModes; m++)
    410             RRModeDestroy(output->modes[m]);
    411         free(output->modes);
    412     }
    413 
    414     for (m = 0; m < output->numUserModes; m++)
    415         RRModeDestroy(output->userModes[m]);
    416     free(output->userModes);
    417 
    418     free(output->crtcs);
    419     free(output->clones);
    420     RRDeleteAllOutputProperties(output);
    421     free(output);
    422     return 1;
    423 }
    424 
    425 /*
    426  * Initialize output type
    427  */
    428 Bool
    429 RROutputInit(void)
    430 {
    431     RROutputType = CreateNewResourceType(RROutputDestroyResource, "OUTPUT");
    432     if (!RROutputType)
    433         return FALSE;
    434 
    435     return TRUE;
    436 }
    437 
    438 /*
    439  * Initialize output type error value
    440  */
    441 void
    442 RROutputInitErrorValue(void)
    443 {
    444     SetResourceTypeErrorValue(RROutputType, RRErrorBase + BadRROutput);
    445 }
    446 
    447 #define OutputInfoExtra	(SIZEOF(xRRGetOutputInfoReply) - 32)
    448 
    449 int
    450 ProcRRGetOutputInfo(ClientPtr client)
    451 {
    452     REQUEST(xRRGetOutputInfoReq);
    453     xRRGetOutputInfoReply rep;
    454     RROutputPtr output;
    455     CARD8 *extra;
    456     unsigned long extraLen;
    457     ScreenPtr pScreen;
    458     rrScrPrivPtr pScrPriv;
    459     RRCrtc *crtcs;
    460     RRMode *modes;
    461     RROutput *clones;
    462     char *name;
    463     int i;
    464     Bool leased;
    465 
    466     REQUEST_SIZE_MATCH(xRRGetOutputInfoReq);
    467     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
    468 
    469     leased = RROutputIsLeased(output);
    470 
    471     pScreen = output->pScreen;
    472     pScrPriv = rrGetScrPriv(pScreen);
    473 
    474     if (leased) {
    475         rep = (xRRGetOutputInfoReply) {
    476             .type = X_Reply,
    477             .status = RRSetConfigSuccess,
    478             .sequenceNumber = client->sequence,
    479             .length = bytes_to_int32(OutputInfoExtra),
    480             .timestamp = pScrPriv->lastSetTime.milliseconds,
    481             .crtc = None,
    482             .mmWidth = 0,
    483             .mmHeight = 0,
    484             .connection = RR_Disconnected,
    485             .subpixelOrder = SubPixelUnknown,
    486             .nCrtcs = 0,
    487             .nModes = 0,
    488             .nPreferred = 0,
    489             .nClones = 0,
    490             .nameLength = output->nameLength
    491         };
    492         extraLen = bytes_to_int32(rep.nameLength) << 2;
    493         if (extraLen) {
    494             rep.length += bytes_to_int32(extraLen);
    495             extra = calloc(1, extraLen);
    496             if (!extra)
    497                 return BadAlloc;
    498         }
    499         else
    500             extra = NULL;
    501 
    502         name = (char *) extra;
    503     } else {
    504         rep = (xRRGetOutputInfoReply) {
    505             .type = X_Reply,
    506             .status = RRSetConfigSuccess,
    507             .sequenceNumber = client->sequence,
    508             .length = bytes_to_int32(OutputInfoExtra),
    509             .timestamp = pScrPriv->lastSetTime.milliseconds,
    510             .crtc = output->crtc ? output->crtc->id : None,
    511             .mmWidth = output->mmWidth,
    512             .mmHeight = output->mmHeight,
    513             .connection = output->nonDesktop ? RR_Disconnected : output->connection,
    514             .subpixelOrder = output->subpixelOrder,
    515             .nCrtcs = output->numCrtcs,
    516             .nModes = output->numModes + output->numUserModes,
    517             .nPreferred = output->numPreferred,
    518             .nClones = output->numClones,
    519             .nameLength = output->nameLength
    520         };
    521         extraLen = ((output->numCrtcs +
    522                      output->numModes + output->numUserModes +
    523                      output->numClones + bytes_to_int32(rep.nameLength)) << 2);
    524 
    525         if (extraLen) {
    526             rep.length += bytes_to_int32(extraLen);
    527             extra = calloc(1, extraLen);
    528             if (!extra)
    529                 return BadAlloc;
    530         }
    531         else
    532             extra = NULL;
    533 
    534         crtcs = (RRCrtc *) extra;
    535         modes = (RRMode *) (crtcs + output->numCrtcs);
    536         clones = (RROutput *) (modes + output->numModes + output->numUserModes);
    537         name = (char *) (clones + output->numClones);
    538 
    539         for (i = 0; i < output->numCrtcs; i++) {
    540             crtcs[i] = output->crtcs[i]->id;
    541             if (client->swapped)
    542                 swapl(&crtcs[i]);
    543         }
    544         for (i = 0; i < output->numModes + output->numUserModes; i++) {
    545             if (i < output->numModes)
    546                 modes[i] = output->modes[i]->mode.id;
    547             else
    548                 modes[i] = output->userModes[i - output->numModes]->mode.id;
    549             if (client->swapped)
    550                 swapl(&modes[i]);
    551         }
    552         for (i = 0; i < output->numClones; i++) {
    553             clones[i] = output->clones[i]->id;
    554             if (client->swapped)
    555                 swapl(&clones[i]);
    556         }
    557     }
    558     memcpy(name, output->name, output->nameLength);
    559     if (client->swapped) {
    560         swaps(&rep.sequenceNumber);
    561         swapl(&rep.length);
    562         swapl(&rep.timestamp);
    563         swapl(&rep.crtc);
    564         swapl(&rep.mmWidth);
    565         swapl(&rep.mmHeight);
    566         swaps(&rep.nCrtcs);
    567         swaps(&rep.nModes);
    568         swaps(&rep.nPreferred);
    569         swaps(&rep.nClones);
    570         swaps(&rep.nameLength);
    571     }
    572     WriteToClient(client, sizeof(xRRGetOutputInfoReply), &rep);
    573     if (extraLen) {
    574         WriteToClient(client, extraLen, extra);
    575         free(extra);
    576     }
    577 
    578     return Success;
    579 }
    580 
    581 static void
    582 RRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv, RROutputPtr output)
    583 {
    584     if (pScrPriv->primaryOutput == output)
    585         return;
    586 
    587     /* clear the old primary */
    588     if (pScrPriv->primaryOutput) {
    589         RROutputChanged(pScrPriv->primaryOutput, 0);
    590         pScrPriv->primaryOutput = NULL;
    591     }
    592 
    593     /* set the new primary */
    594     if (output) {
    595         pScrPriv->primaryOutput = output;
    596         RROutputChanged(output, 0);
    597     }
    598 
    599     pScrPriv->layoutChanged = TRUE;
    600 
    601     RRTellChanged(pScreen);
    602 }
    603 
    604 int
    605 ProcRRSetOutputPrimary(ClientPtr client)
    606 {
    607     REQUEST(xRRSetOutputPrimaryReq);
    608     RROutputPtr output = NULL;
    609     WindowPtr pWin;
    610     rrScrPrivPtr pScrPriv;
    611     int ret;
    612     ScreenPtr secondary;
    613 
    614     REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq);
    615 
    616     ret = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
    617     if (ret != Success)
    618         return ret;
    619 
    620     if (stuff->output) {
    621         VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
    622 
    623         if (RROutputIsLeased(output))
    624             return BadAccess;
    625 
    626         if (!output->pScreen->isGPU && output->pScreen != pWin->drawable.pScreen) {
    627             client->errorValue = stuff->window;
    628             return BadMatch;
    629         }
    630         if (output->pScreen->isGPU && output->pScreen->current_primary != pWin->drawable.pScreen) {
    631             client->errorValue = stuff->window;
    632             return BadMatch;
    633         }
    634     }
    635 
    636     pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
    637     if (pScrPriv)
    638     {
    639         RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output);
    640 
    641         xorg_list_for_each_entry(secondary,
    642                                  &pWin->drawable.pScreen->secondary_list,
    643                                  secondary_head) {
    644             if (secondary->is_output_secondary)
    645                 RRSetPrimaryOutput(secondary, rrGetScrPriv(secondary), output);
    646         }
    647     }
    648 
    649     return Success;
    650 }
    651 
    652 int
    653 ProcRRGetOutputPrimary(ClientPtr client)
    654 {
    655     REQUEST(xRRGetOutputPrimaryReq);
    656     WindowPtr pWin;
    657     rrScrPrivPtr pScrPriv;
    658     xRRGetOutputPrimaryReply rep;
    659     RROutputPtr primary = NULL;
    660     int rc;
    661 
    662     REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq);
    663 
    664     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
    665     if (rc != Success)
    666         return rc;
    667 
    668     pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
    669     if (pScrPriv)
    670         primary = pScrPriv->primaryOutput;
    671 
    672     rep = (xRRGetOutputPrimaryReply) {
    673         .type = X_Reply,
    674         .sequenceNumber = client->sequence,
    675         .output = primary ? primary->id : None
    676     };
    677 
    678     if (client->swapped) {
    679         swaps(&rep.sequenceNumber);
    680         swapl(&rep.output);
    681     }
    682 
    683     WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep);
    684 
    685     return Success;
    686 }