| 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 | |
| 26 | RESTYPE RROutputType; |
| 27 | |
| 28 | /* |
| 29 | * Notify the output of some change |
| 30 | */ |
| 31 | void |
| 32 | RROutputChanged(RROutputPtr output, Bool configChanged) |
| 33 | { |
| 34 | ScreenPtr pScreen = output->pScreen; |
| 35 | |
| 36 | output->changed = TRUE; |
| 37 | if (pScreen) { |
| 38 | rrScrPriv(pScreen); |
| 39 | RRSetChanged(pScreen); |
| 40 | if (configChanged) |
| 41 | pScrPriv->configChanged = TRUE; |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | /* |
| 46 | * Create an output |
| 47 | */ |
| 48 | |
| 49 | RROutputPtr |
| 50 | RROutputCreate(ScreenPtr pScreen, |
| 51 | const char *name, int nameLength, void *devPrivate) |
| 52 | { |
| 53 | RROutputPtr output; |
| 54 | RROutputPtr *outputs; |
| 55 | rrScrPrivPtr pScrPriv; |
| 56 | |
| 57 | if (!RRInit()) |
| 58 | return NULL; |
| 59 | |
| 60 | pScrPriv = rrGetScrPriv(pScreen); |
| 61 | |
| 62 | if (pScrPriv->numOutputs) |
| 63 | outputs = realloc(pScrPriv->outputs, |
| 64 | (pScrPriv->numOutputs + 1) * sizeof(RROutputPtr)); |
| 65 | else |
| 66 | outputs = malloc(sizeof(RROutputPtr)); |
| 67 | if (!outputs) |
| 68 | return FALSE; |
| 69 | |
| 70 | pScrPriv->outputs = outputs; |
| 71 | |
| 72 | output = malloc(sizeof(RROutputRec) + nameLength + 1); |
| 73 | if (!output) |
| 74 | return NULL; |
| 75 | output->id = FakeClientID(0); |
| 76 | output->pScreen = pScreen; |
| 77 | output->name = (char *) (output + 1); |
| 78 | output->nameLength = nameLength; |
| 79 | memcpy(output->name, name, nameLength); |
| 80 | output->name[nameLength] = '\0'; |
| 81 | output->connection = RR_UnknownConnection; |
| 82 | output->subpixelOrder = SubPixelUnknown; |
| 83 | output->mmWidth = 0; |
| 84 | output->mmHeight = 0; |
| 85 | output->crtc = NULL; |
| 86 | output->numCrtcs = 0; |
| 87 | output->crtcs = NULL; |
| 88 | output->numClones = 0; |
| 89 | output->clones = NULL; |
| 90 | output->numModes = 0; |
| 91 | output->numPreferred = 0; |
| 92 | output->modes = NULL; |
| 93 | output->numUserModes = 0; |
| 94 | output->userModes = NULL; |
| 95 | output->properties = NULL; |
| 96 | output->pendingProperties = FALSE; |
| 97 | output->changed = FALSE; |
| 98 | output->devPrivate = devPrivate; |
| 99 | |
| 100 | if (!AddResource(output->id, RROutputType, (pointer) output)) |
| 101 | return NULL; |
| 102 | |
| 103 | pScrPriv->outputs[pScrPriv->numOutputs++] = output; |
| 104 | |
| 105 | RRResourcesChanged(pScreen); |
| 106 | |
| 107 | return output; |
| 108 | } |
| 109 | |
| 110 | /* |
| 111 | * Notify extension that output parameters have been changed |
| 112 | */ |
| 113 | Bool |
| 114 | RROutputSetClones(RROutputPtr output, RROutputPtr * clones, int numClones) |
| 115 | { |
| 116 | RROutputPtr *newClones; |
| 117 | int i; |
| 118 | |
| 119 | if (numClones == output->numClones) { |
| 120 | for (i = 0; i < numClones; i++) |
| 121 | if (output->clones[i] != clones[i]) |
| 122 | break; |
| 123 | if (i == numClones) |
| 124 | return TRUE; |
| 125 | } |
| 126 | if (numClones) { |
| 127 | newClones = malloc(numClones * sizeof(RROutputPtr)); |
| 128 | if (!newClones) |
| 129 | return FALSE; |
| 130 | } |
| 131 | else |
| 132 | newClones = NULL; |
| 133 | free(output->clones); |
| 134 | memcpy(newClones, clones, numClones * sizeof(RROutputPtr)); |
| 135 | output->clones = newClones; |
| 136 | output->numClones = numClones; |
| 137 | RROutputChanged(output, TRUE); |
| 138 | return TRUE; |
| 139 | } |
| 140 | |
| 141 | Bool |
| 142 | RROutputSetModes(RROutputPtr output, |
| 143 | RRModePtr * modes, int numModes, int numPreferred) |
| 144 | { |
| 145 | RRModePtr *newModes; |
| 146 | int i; |
| 147 | |
| 148 | if (numModes == output->numModes && numPreferred == output->numPreferred) { |
| 149 | for (i = 0; i < numModes; i++) |
| 150 | if (output->modes[i] != modes[i]) |
| 151 | break; |
| 152 | if (i == numModes) { |
| 153 | for (i = 0; i < numModes; i++) |
| 154 | RRModeDestroy(modes[i]); |
| 155 | return TRUE; |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | if (numModes) { |
| 160 | newModes = malloc(numModes * sizeof(RRModePtr)); |
| 161 | if (!newModes) |
| 162 | return FALSE; |
| 163 | } |
| 164 | else |
| 165 | newModes = NULL; |
| 166 | if (output->modes) { |
| 167 | for (i = 0; i < output->numModes; i++) |
| 168 | RRModeDestroy(output->modes[i]); |
| 169 | free(output->modes); |
| 170 | } |
| 171 | memcpy(newModes, modes, numModes * sizeof(RRModePtr)); |
| 172 | output->modes = newModes; |
| 173 | output->numModes = numModes; |
| 174 | output->numPreferred = numPreferred; |
| 175 | RROutputChanged(output, TRUE); |
| 176 | return TRUE; |
| 177 | } |
| 178 | |
| 179 | int |
| 180 | RROutputAddUserMode(RROutputPtr output, RRModePtr mode) |
| 181 | { |
| 182 | int m; |
| 183 | ScreenPtr pScreen = output->pScreen; |
| 184 | |
| 185 | rrScrPriv(pScreen); |
| 186 | RRModePtr *newModes; |
| 187 | |
| 188 | /* Check to see if this mode is already listed for this output */ |
| 189 | for (m = 0; m < output->numModes + output->numUserModes; m++) { |
| 190 | RRModePtr e = (m < output->numModes ? |
| 191 | output->modes[m] : |
| 192 | output->userModes[m - output->numModes]); |
| 193 | if (mode == e) |
| 194 | return Success; |
| 195 | } |
| 196 | |
| 197 | /* Check with the DDX to see if this mode is OK */ |
| 198 | if (pScrPriv->rrOutputValidateMode) |
| 199 | if (!pScrPriv->rrOutputValidateMode(pScreen, output, mode)) |
| 200 | return BadMatch; |
| 201 | |
| 202 | if (output->userModes) |
| 203 | newModes = realloc(output->userModes, |
| 204 | (output->numUserModes + 1) * sizeof(RRModePtr)); |
| 205 | else |
| 206 | newModes = malloc(sizeof(RRModePtr)); |
| 207 | if (!newModes) |
| 208 | return BadAlloc; |
| 209 | |
| 210 | output->userModes = newModes; |
| 211 | output->userModes[output->numUserModes++] = mode; |
| 212 | ++mode->refcnt; |
| 213 | RROutputChanged(output, TRUE); |
| 214 | RRTellChanged(pScreen); |
| 215 | return Success; |
| 216 | } |
| 217 | |
| 218 | int |
| 219 | RROutputDeleteUserMode(RROutputPtr output, RRModePtr mode) |
| 220 | { |
| 221 | int m; |
| 222 | |
| 223 | /* Find this mode in the user mode list */ |
| 224 | for (m = 0; m < output->numUserModes; m++) { |
| 225 | RRModePtr e = output->userModes[m]; |
| 226 | |
| 227 | if (mode == e) |
| 228 | break; |
| 229 | } |
| 230 | /* Not there, access error */ |
| 231 | if (m == output->numUserModes) |
| 232 | return BadAccess; |
| 233 | |
| 234 | /* make sure the mode isn't active for this output */ |
| 235 | if (output->crtc && output->crtc->mode == mode) |
| 236 | return BadMatch; |
| 237 | |
| 238 | memmove(output->userModes + m, output->userModes + m + 1, |
| 239 | (output->numUserModes - m - 1) * sizeof(RRModePtr)); |
| 240 | output->numUserModes--; |
| 241 | RRModeDestroy(mode); |
| 242 | return Success; |
| 243 | } |
| 244 | |
| 245 | Bool |
| 246 | RROutputSetCrtcs(RROutputPtr output, RRCrtcPtr * crtcs, int numCrtcs) |
| 247 | { |
| 248 | RRCrtcPtr *newCrtcs; |
| 249 | int i; |
| 250 | |
| 251 | if (numCrtcs == output->numCrtcs) { |
| 252 | for (i = 0; i < numCrtcs; i++) |
| 253 | if (output->crtcs[i] != crtcs[i]) |
| 254 | break; |
| 255 | if (i == numCrtcs) |
| 256 | return TRUE; |
| 257 | } |
| 258 | if (numCrtcs) { |
| 259 | newCrtcs = malloc(numCrtcs * sizeof(RRCrtcPtr)); |
| 260 | if (!newCrtcs) |
| 261 | return FALSE; |
| 262 | } |
| 263 | else |
| 264 | newCrtcs = NULL; |
| 265 | free(output->crtcs); |
| 266 | memcpy(newCrtcs, crtcs, numCrtcs * sizeof(RRCrtcPtr)); |
| 267 | output->crtcs = newCrtcs; |
| 268 | output->numCrtcs = numCrtcs; |
| 269 | RROutputChanged(output, TRUE); |
| 270 | return TRUE; |
| 271 | } |
| 272 | |
| 273 | Bool |
| 274 | RROutputSetConnection(RROutputPtr output, CARD8 connection) |
| 275 | { |
| 276 | if (output->connection == connection) |
| 277 | return TRUE; |
| 278 | output->connection = connection; |
| 279 | RROutputChanged(output, TRUE); |
| 280 | return TRUE; |
| 281 | } |
| 282 | |
| 283 | Bool |
| 284 | RROutputSetSubpixelOrder(RROutputPtr output, int subpixelOrder) |
| 285 | { |
| 286 | if (output->subpixelOrder == subpixelOrder) |
| 287 | return TRUE; |
| 288 | |
| 289 | output->subpixelOrder = subpixelOrder; |
| 290 | RROutputChanged(output, FALSE); |
| 291 | return TRUE; |
| 292 | } |
| 293 | |
| 294 | Bool |
| 295 | RROutputSetPhysicalSize(RROutputPtr output, int mmWidth, int mmHeight) |
| 296 | { |
| 297 | if (output->mmWidth == mmWidth && output->mmHeight == mmHeight) |
| 298 | return TRUE; |
| 299 | output->mmWidth = mmWidth; |
| 300 | output->mmHeight = mmHeight; |
| 301 | RROutputChanged(output, FALSE); |
| 302 | return TRUE; |
| 303 | } |
| 304 | |
| 305 | void |
| 306 | RRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output) |
| 307 | { |
| 308 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 309 | |
| 310 | rrScrPriv(pScreen); |
| 311 | RRCrtcPtr crtc = output->crtc; |
| 312 | RRModePtr mode = crtc ? crtc->mode : NULL; |
| 313 | |
| 314 | xRROutputChangeNotifyEvent oe = { |
| 315 | .type = RRNotify + RREventBase, |
| 316 | .subCode = RRNotify_OutputChange, |
| 317 | .timestamp = pScrPriv->lastSetTime.milliseconds, |
| 318 | .configTimestamp = pScrPriv->lastConfigTime.milliseconds, |
| 319 | .window = pWin->drawable.id, |
| 320 | .output = output->id, |
| 321 | .crtc = crtc ? crtc->id : None, |
| 322 | .mode = mode ? mode->mode.id : None, |
| 323 | .rotation = crtc ? crtc->rotation : RR_Rotate_0, |
| 324 | .connection = output->connection, |
| 325 | .subpixelOrder = output->subpixelOrder |
| 326 | }; |
| 327 | WriteEventsToClient(client, 1, (xEvent *) &oe); |
| 328 | } |
| 329 | |
| 330 | /* |
| 331 | * Destroy a Output at shutdown |
| 332 | */ |
| 333 | void |
| 334 | RROutputDestroy(RROutputPtr output) |
| 335 | { |
| 336 | FreeResource(output->id, 0); |
| 337 | } |
| 338 | |
| 339 | static int |
| 340 | RROutputDestroyResource(pointer value, XID pid) |
| 341 | { |
| 342 | RROutputPtr output = (RROutputPtr) value; |
| 343 | ScreenPtr pScreen = output->pScreen; |
| 344 | int m; |
| 345 | |
| 346 | if (pScreen) { |
| 347 | rrScrPriv(pScreen); |
| 348 | int i; |
| 349 | |
| 350 | if (pScrPriv->primaryOutput == output) |
| 351 | pScrPriv->primaryOutput = NULL; |
| 352 | |
| 353 | for (i = 0; i < pScrPriv->numOutputs; i++) { |
| 354 | if (pScrPriv->outputs[i] == output) { |
| 355 | memmove(pScrPriv->outputs + i, pScrPriv->outputs + i + 1, |
| 356 | (pScrPriv->numOutputs - (i + 1)) * sizeof(RROutputPtr)); |
| 357 | --pScrPriv->numOutputs; |
| 358 | break; |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | RRResourcesChanged(pScreen); |
| 363 | } |
| 364 | if (output->modes) { |
| 365 | for (m = 0; m < output->numModes; m++) |
| 366 | RRModeDestroy(output->modes[m]); |
| 367 | free(output->modes); |
| 368 | } |
| 369 | |
| 370 | for (m = 0; m < output->numUserModes; m++) |
| 371 | RRModeDestroy(output->userModes[m]); |
| 372 | free(output->userModes); |
| 373 | |
| 374 | free(output->crtcs); |
| 375 | free(output->clones); |
| 376 | RRDeleteAllOutputProperties(output); |
| 377 | free(output); |
| 378 | return 1; |
| 379 | } |
| 380 | |
| 381 | /* |
| 382 | * Initialize output type |
| 383 | */ |
| 384 | Bool |
| 385 | RROutputInit(void) |
| 386 | { |
| 387 | RROutputType = CreateNewResourceType(RROutputDestroyResource, "OUTPUT"); |
| 388 | if (!RROutputType) |
| 389 | return FALSE; |
| 390 | |
| 391 | return TRUE; |
| 392 | } |
| 393 | |
| 394 | /* |
| 395 | * Initialize output type error value |
| 396 | */ |
| 397 | void |
| 398 | RROutputInitErrorValue(void) |
| 399 | { |
| 400 | SetResourceTypeErrorValue(RROutputType, RRErrorBase + BadRROutput); |
| 401 | } |
| 402 | |
| 403 | #define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32) |
| 404 | |
| 405 | int |
| 406 | ProcRRGetOutputInfo(ClientPtr client) |
| 407 | { |
| 408 | REQUEST(xRRGetOutputInfoReq); |
| 409 | xRRGetOutputInfoReply rep; |
| 410 | RROutputPtr output; |
| 411 | CARD8 *extra; |
| 412 | unsigned long extraLen; |
| 413 | ScreenPtr pScreen; |
| 414 | rrScrPrivPtr pScrPriv; |
| 415 | RRCrtc *crtcs; |
| 416 | RRMode *modes; |
| 417 | RROutput *clones; |
| 418 | char *name; |
| 419 | int i; |
| 420 | |
| 421 | REQUEST_SIZE_MATCH(xRRGetOutputInfoReq); |
| 422 | VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); |
| 423 | |
| 424 | pScreen = output->pScreen; |
| 425 | pScrPriv = rrGetScrPriv(pScreen); |
| 426 | |
| 427 | rep = (xRRGetOutputInfoReply) { |
| 428 | .type = X_Reply, |
| 429 | .status = RRSetConfigSuccess, |
| 430 | .sequenceNumber = client->sequence, |
| 431 | .length = bytes_to_int32(OutputInfoExtra), |
| 432 | .timestamp = pScrPriv->lastSetTime.milliseconds, |
| 433 | .crtc = output->crtc ? output->crtc->id : None, |
| 434 | .mmWidth = output->mmWidth, |
| 435 | .mmHeight = output->mmHeight, |
| 436 | .connection = output->connection, |
| 437 | .subpixelOrder = output->subpixelOrder, |
| 438 | .nCrtcs = output->numCrtcs, |
| 439 | .nModes = output->numModes + output->numUserModes, |
| 440 | .nPreferred = output->numPreferred, |
| 441 | .nClones = output->numClones, |
| 442 | .nameLength = output->nameLength |
| 443 | }; |
| 444 | extraLen = ((output->numCrtcs + |
| 445 | output->numModes + output->numUserModes + |
| 446 | output->numClones + bytes_to_int32(rep.nameLength)) << 2); |
| 447 | |
| 448 | if (extraLen) { |
| 449 | rep.length += bytes_to_int32(extraLen); |
| 450 | extra = malloc(extraLen); |
| 451 | if (!extra) |
| 452 | return BadAlloc; |
| 453 | } |
| 454 | else |
| 455 | extra = NULL; |
| 456 | |
| 457 | crtcs = (RRCrtc *) extra; |
| 458 | modes = (RRMode *) (crtcs + output->numCrtcs); |
| 459 | clones = (RROutput *) (modes + output->numModes + output->numUserModes); |
| 460 | name = (char *) (clones + output->numClones); |
| 461 | |
| 462 | for (i = 0; i < output->numCrtcs; i++) { |
| 463 | crtcs[i] = output->crtcs[i]->id; |
| 464 | if (client->swapped) |
| 465 | swapl(&crtcs[i]); |
| 466 | } |
| 467 | for (i = 0; i < output->numModes + output->numUserModes; i++) { |
| 468 | if (i < output->numModes) |
| 469 | modes[i] = output->modes[i]->mode.id; |
| 470 | else |
| 471 | modes[i] = output->userModes[i - output->numModes]->mode.id; |
| 472 | if (client->swapped) |
| 473 | swapl(&modes[i]); |
| 474 | } |
| 475 | for (i = 0; i < output->numClones; i++) { |
| 476 | clones[i] = output->clones[i]->id; |
| 477 | if (client->swapped) |
| 478 | swapl(&clones[i]); |
| 479 | } |
| 480 | memcpy(name, output->name, output->nameLength); |
| 481 | if (client->swapped) { |
| 482 | swaps(&rep.sequenceNumber); |
| 483 | swapl(&rep.length); |
| 484 | swapl(&rep.timestamp); |
| 485 | swapl(&rep.crtc); |
| 486 | swapl(&rep.mmWidth); |
| 487 | swapl(&rep.mmHeight); |
| 488 | swaps(&rep.nCrtcs); |
| 489 | swaps(&rep.nModes); |
| 490 | swaps(&rep.nClones); |
| 491 | swaps(&rep.nameLength); |
| 492 | } |
| 493 | WriteToClient(client, sizeof(xRRGetOutputInfoReply), &rep); |
| 494 | if (extraLen) { |
| 495 | WriteToClient(client, extraLen, extra); |
| 496 | free(extra); |
| 497 | } |
| 498 | |
| 499 | return Success; |
| 500 | } |
| 501 | |
| 502 | static void |
| 503 | RRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv, RROutputPtr output) |
| 504 | { |
| 505 | if (pScrPriv->primaryOutput == output) |
| 506 | return; |
| 507 | |
| 508 | /* clear the old primary */ |
| 509 | if (pScrPriv->primaryOutput) { |
| 510 | RROutputChanged(pScrPriv->primaryOutput, 0); |
| 511 | pScrPriv->primaryOutput = NULL; |
| 512 | } |
| 513 | |
| 514 | /* set the new primary */ |
| 515 | if (output) { |
| 516 | pScrPriv->primaryOutput = output; |
| 517 | RROutputChanged(output, 0); |
| 518 | } |
| 519 | |
| 520 | pScrPriv->layoutChanged = TRUE; |
| 521 | |
| 522 | RRTellChanged(pScreen); |
| 523 | } |
| 524 | |
| 525 | int |
| 526 | ProcRRSetOutputPrimary(ClientPtr client) |
| 527 | { |
| 528 | REQUEST(xRRSetOutputPrimaryReq); |
| 529 | RROutputPtr output = NULL; |
| 530 | WindowPtr pWin; |
| 531 | rrScrPrivPtr pScrPriv; |
| 532 | int ret; |
| 533 | |
| 534 | REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq); |
| 535 | |
| 536 | ret = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); |
| 537 | if (ret != Success) |
| 538 | return ret; |
| 539 | |
| 540 | if (stuff->output) { |
| 541 | VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); |
| 542 | |
| 543 | if (output->pScreen != pWin->drawable.pScreen) { |
| 544 | client->errorValue = stuff->window; |
| 545 | return BadMatch; |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); |
| 550 | if (pScrPriv) |
| 551 | RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output); |
| 552 | |
| 553 | return Success; |
| 554 | } |
| 555 | |
| 556 | int |
| 557 | ProcRRGetOutputPrimary(ClientPtr client) |
| 558 | { |
| 559 | REQUEST(xRRGetOutputPrimaryReq); |
| 560 | WindowPtr pWin; |
| 561 | rrScrPrivPtr pScrPriv; |
| 562 | xRRGetOutputPrimaryReply rep; |
| 563 | RROutputPtr primary = NULL; |
| 564 | int rc; |
| 565 | |
| 566 | REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq); |
| 567 | |
| 568 | rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); |
| 569 | if (rc != Success) |
| 570 | return rc; |
| 571 | |
| 572 | pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); |
| 573 | if (pScrPriv) |
| 574 | primary = pScrPriv->primaryOutput; |
| 575 | |
| 576 | rep = (xRRGetOutputPrimaryReply) { |
| 577 | .type = X_Reply, |
| 578 | .sequenceNumber = client->sequence, |
| 579 | .output = primary ? primary->id : None |
| 580 | }; |
| 581 | |
| 582 | if (client->swapped) { |
| 583 | swaps(&rep.sequenceNumber); |
| 584 | swapl(&rep.output); |
| 585 | } |
| 586 | |
| 587 | WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep); |
| 588 | |
| 589 | return Success; |
| 590 | } |