105b261ecSmrg/* 205b261ecSmrg * Copyright © 2006 Keith Packard 34642e01fSmrg * Copyright © 2008 Red Hat, Inc. 405b261ecSmrg * 505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 705b261ecSmrg * the above copyright notice appear in all copies and that both that copyright 805b261ecSmrg * notice and this permission notice appear in supporting documentation, and 905b261ecSmrg * that the name of the copyright holders not be used in advertising or 1005b261ecSmrg * publicity pertaining to distribution of the software without specific, 1105b261ecSmrg * written prior permission. The copyright holders make no representations 1205b261ecSmrg * about the suitability of this software for any purpose. It is provided "as 1305b261ecSmrg * is" without express or implied warranty. 1405b261ecSmrg * 1505b261ecSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1705b261ecSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2105b261ecSmrg * OF THIS SOFTWARE. 2205b261ecSmrg */ 2305b261ecSmrg 2405b261ecSmrg#include "randrstr.h" 251b5d61b8Smrg#include <X11/Xatom.h> 2605b261ecSmrg 2735c4bbdfSmrgRESTYPE RROutputType; 2805b261ecSmrg 2905b261ecSmrg/* 3005b261ecSmrg * Notify the output of some change 3105b261ecSmrg */ 3205b261ecSmrgvoid 3335c4bbdfSmrgRROutputChanged(RROutputPtr output, Bool configChanged) 3405b261ecSmrg{ 35ed6184dfSmrg /* set changed bits on the primary screen only */ 3635c4bbdfSmrg ScreenPtr pScreen = output->pScreen; 37ed6184dfSmrg rrScrPrivPtr primarysp; 3835c4bbdfSmrg 3905b261ecSmrg output->changed = TRUE; 4035c4bbdfSmrg if (!pScreen) 4135c4bbdfSmrg return; 4235c4bbdfSmrg 4335c4bbdfSmrg if (pScreen->isGPU) { 44ed6184dfSmrg ScreenPtr primary = pScreen->current_primary; 45ed6184dfSmrg if (!primary) 4635c4bbdfSmrg return; 47ed6184dfSmrg primarysp = rrGetScrPriv(primary); 4805b261ecSmrg } 4935c4bbdfSmrg else { 50ed6184dfSmrg primarysp = rrGetScrPriv(pScreen); 5135c4bbdfSmrg } 5235c4bbdfSmrg 5335c4bbdfSmrg RRSetChanged(pScreen); 5435c4bbdfSmrg if (configChanged) 55ed6184dfSmrg primarysp->configChanged = TRUE; 5605b261ecSmrg} 5705b261ecSmrg 5805b261ecSmrg/* 5905b261ecSmrg * Create an output 6005b261ecSmrg */ 6105b261ecSmrg 6205b261ecSmrgRROutputPtr 6335c4bbdfSmrgRROutputCreate(ScreenPtr pScreen, 6435c4bbdfSmrg const char *name, int nameLength, void *devPrivate) 6505b261ecSmrg{ 6635c4bbdfSmrg RROutputPtr output; 6735c4bbdfSmrg RROutputPtr *outputs; 6835c4bbdfSmrg rrScrPrivPtr pScrPriv; 691b5d61b8Smrg Atom nonDesktopAtom; 7005b261ecSmrg 7105b261ecSmrg if (!RRInit()) 7235c4bbdfSmrg return NULL; 7335c4bbdfSmrg 7405b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 7505b261ecSmrg 761b5d61b8Smrg outputs = reallocarray(pScrPriv->outputs, 771b5d61b8Smrg pScrPriv->numOutputs + 1, sizeof(RROutputPtr)); 7805b261ecSmrg if (!outputs) 791b5d61b8Smrg return NULL; 8005b261ecSmrg 8105b261ecSmrg pScrPriv->outputs = outputs; 8235c4bbdfSmrg 8335c4bbdfSmrg output = malloc(sizeof(RROutputRec) + nameLength + 1); 8405b261ecSmrg if (!output) 8535c4bbdfSmrg return NULL; 8635c4bbdfSmrg output->id = FakeClientID(0); 8705b261ecSmrg output->pScreen = pScreen; 8805b261ecSmrg output->name = (char *) (output + 1); 8905b261ecSmrg output->nameLength = nameLength; 9035c4bbdfSmrg memcpy(output->name, name, nameLength); 9105b261ecSmrg output->name[nameLength] = '\0'; 9205b261ecSmrg output->connection = RR_UnknownConnection; 9305b261ecSmrg output->subpixelOrder = SubPixelUnknown; 9405b261ecSmrg output->mmWidth = 0; 9505b261ecSmrg output->mmHeight = 0; 9605b261ecSmrg output->crtc = NULL; 9705b261ecSmrg output->numCrtcs = 0; 9805b261ecSmrg output->crtcs = NULL; 9905b261ecSmrg output->numClones = 0; 10005b261ecSmrg output->clones = NULL; 10105b261ecSmrg output->numModes = 0; 10205b261ecSmrg output->numPreferred = 0; 10305b261ecSmrg output->modes = NULL; 10405b261ecSmrg output->numUserModes = 0; 10505b261ecSmrg output->userModes = NULL; 10605b261ecSmrg output->properties = NULL; 1074642e01fSmrg output->pendingProperties = FALSE; 10805b261ecSmrg output->changed = FALSE; 1091b5d61b8Smrg output->nonDesktop = FALSE; 11005b261ecSmrg output->devPrivate = devPrivate; 11135c4bbdfSmrg 11235c4bbdfSmrg if (!AddResource(output->id, RROutputType, (void *) output)) 11335c4bbdfSmrg return NULL; 11405b261ecSmrg 11505b261ecSmrg pScrPriv->outputs[pScrPriv->numOutputs++] = output; 11635c4bbdfSmrg 1171b5d61b8Smrg nonDesktopAtom = MakeAtom(RR_PROPERTY_NON_DESKTOP, strlen(RR_PROPERTY_NON_DESKTOP), TRUE); 1181b5d61b8Smrg if (nonDesktopAtom != BAD_RESOURCE) { 1191b5d61b8Smrg static const INT32 values[2] = { 0, 1 }; 1201b5d61b8Smrg (void) RRConfigureOutputProperty(output, nonDesktopAtom, FALSE, FALSE, FALSE, 1211b5d61b8Smrg 2, values); 1221b5d61b8Smrg } 1231b5d61b8Smrg RROutputSetNonDesktop(output, FALSE); 12435c4bbdfSmrg RRResourcesChanged(pScreen); 12535c4bbdfSmrg 12605b261ecSmrg return output; 12705b261ecSmrg} 12805b261ecSmrg 12905b261ecSmrg/* 13005b261ecSmrg * Notify extension that output parameters have been changed 13105b261ecSmrg */ 13205b261ecSmrgBool 13335c4bbdfSmrgRROutputSetClones(RROutputPtr output, RROutputPtr * clones, int numClones) 13405b261ecSmrg{ 13535c4bbdfSmrg RROutputPtr *newClones; 13635c4bbdfSmrg int i; 13735c4bbdfSmrg 13835c4bbdfSmrg if (numClones == output->numClones) { 13935c4bbdfSmrg for (i = 0; i < numClones; i++) 14035c4bbdfSmrg if (output->clones[i] != clones[i]) 14135c4bbdfSmrg break; 14235c4bbdfSmrg if (i == numClones) 14335c4bbdfSmrg return TRUE; 14405b261ecSmrg } 14535c4bbdfSmrg if (numClones) { 14635c4bbdfSmrg newClones = xallocarray(numClones, sizeof(RROutputPtr)); 14735c4bbdfSmrg if (!newClones) 14835c4bbdfSmrg return FALSE; 14905b261ecSmrg } 15005b261ecSmrg else 15135c4bbdfSmrg newClones = NULL; 1526747b715Smrg free(output->clones); 15335c4bbdfSmrg memcpy(newClones, clones, numClones * sizeof(RROutputPtr)); 15405b261ecSmrg output->clones = newClones; 15505b261ecSmrg output->numClones = numClones; 15635c4bbdfSmrg RROutputChanged(output, TRUE); 15705b261ecSmrg return TRUE; 15805b261ecSmrg} 15905b261ecSmrg 16005b261ecSmrgBool 16135c4bbdfSmrgRROutputSetModes(RROutputPtr output, 16235c4bbdfSmrg RRModePtr * modes, int numModes, int numPreferred) 16305b261ecSmrg{ 16435c4bbdfSmrg RRModePtr *newModes; 16535c4bbdfSmrg int i; 16635c4bbdfSmrg 16735c4bbdfSmrg if (numModes == output->numModes && numPreferred == output->numPreferred) { 16835c4bbdfSmrg for (i = 0; i < numModes; i++) 16935c4bbdfSmrg if (output->modes[i] != modes[i]) 17035c4bbdfSmrg break; 17135c4bbdfSmrg if (i == numModes) { 17235c4bbdfSmrg for (i = 0; i < numModes; i++) 17335c4bbdfSmrg RRModeDestroy(modes[i]); 17435c4bbdfSmrg return TRUE; 17535c4bbdfSmrg } 17605b261ecSmrg } 17705b261ecSmrg 17835c4bbdfSmrg if (numModes) { 17935c4bbdfSmrg newModes = xallocarray(numModes, sizeof(RRModePtr)); 18035c4bbdfSmrg if (!newModes) 18135c4bbdfSmrg return FALSE; 18205b261ecSmrg } 18305b261ecSmrg else 18435c4bbdfSmrg newModes = NULL; 18535c4bbdfSmrg if (output->modes) { 18635c4bbdfSmrg for (i = 0; i < output->numModes; i++) 18735c4bbdfSmrg RRModeDestroy(output->modes[i]); 18835c4bbdfSmrg free(output->modes); 18905b261ecSmrg } 19035c4bbdfSmrg memcpy(newModes, modes, numModes * sizeof(RRModePtr)); 19105b261ecSmrg output->modes = newModes; 19205b261ecSmrg output->numModes = numModes; 19305b261ecSmrg output->numPreferred = numPreferred; 19435c4bbdfSmrg RROutputChanged(output, TRUE); 19505b261ecSmrg return TRUE; 19605b261ecSmrg} 19705b261ecSmrg 19805b261ecSmrgint 19935c4bbdfSmrgRROutputAddUserMode(RROutputPtr output, RRModePtr mode) 20005b261ecSmrg{ 20135c4bbdfSmrg int m; 20235c4bbdfSmrg ScreenPtr pScreen = output->pScreen; 20335c4bbdfSmrg 20405b261ecSmrg rrScrPriv(pScreen); 20535c4bbdfSmrg RRModePtr *newModes; 20605b261ecSmrg 20705b261ecSmrg /* Check to see if this mode is already listed for this output */ 20835c4bbdfSmrg for (m = 0; m < output->numModes + output->numUserModes; m++) { 20935c4bbdfSmrg RRModePtr e = (m < output->numModes ? 21035c4bbdfSmrg output->modes[m] : 21135c4bbdfSmrg output->userModes[m - output->numModes]); 21235c4bbdfSmrg if (mode == e) 21335c4bbdfSmrg return Success; 21405b261ecSmrg } 21505b261ecSmrg 21605b261ecSmrg /* Check with the DDX to see if this mode is OK */ 21705b261ecSmrg if (pScrPriv->rrOutputValidateMode) 21835c4bbdfSmrg if (!pScrPriv->rrOutputValidateMode(pScreen, output, mode)) 21935c4bbdfSmrg return BadMatch; 22005b261ecSmrg 22105b261ecSmrg if (output->userModes) 22235c4bbdfSmrg newModes = reallocarray(output->userModes, 22335c4bbdfSmrg output->numUserModes + 1, sizeof(RRModePtr)); 22405b261ecSmrg else 22535c4bbdfSmrg newModes = malloc(sizeof(RRModePtr)); 22605b261ecSmrg if (!newModes) 22735c4bbdfSmrg return BadAlloc; 22805b261ecSmrg 22905b261ecSmrg output->userModes = newModes; 23005b261ecSmrg output->userModes[output->numUserModes++] = mode; 23105b261ecSmrg ++mode->refcnt; 23235c4bbdfSmrg RROutputChanged(output, TRUE); 23335c4bbdfSmrg RRTellChanged(pScreen); 23405b261ecSmrg return Success; 23505b261ecSmrg} 23605b261ecSmrg 23705b261ecSmrgint 23835c4bbdfSmrgRROutputDeleteUserMode(RROutputPtr output, RRModePtr mode) 23905b261ecSmrg{ 24035c4bbdfSmrg int m; 24135c4bbdfSmrg 24205b261ecSmrg /* Find this mode in the user mode list */ 24335c4bbdfSmrg for (m = 0; m < output->numUserModes; m++) { 24435c4bbdfSmrg RRModePtr e = output->userModes[m]; 24505b261ecSmrg 24635c4bbdfSmrg if (mode == e) 24735c4bbdfSmrg break; 24805b261ecSmrg } 24905b261ecSmrg /* Not there, access error */ 25005b261ecSmrg if (m == output->numUserModes) 25135c4bbdfSmrg return BadAccess; 25205b261ecSmrg 25305b261ecSmrg /* make sure the mode isn't active for this output */ 25405b261ecSmrg if (output->crtc && output->crtc->mode == mode) 25535c4bbdfSmrg return BadMatch; 25605b261ecSmrg 25735c4bbdfSmrg memmove(output->userModes + m, output->userModes + m + 1, 25835c4bbdfSmrg (output->numUserModes - m - 1) * sizeof(RRModePtr)); 25905b261ecSmrg output->numUserModes--; 26035c4bbdfSmrg RRModeDestroy(mode); 26105b261ecSmrg return Success; 26205b261ecSmrg} 26305b261ecSmrg 26405b261ecSmrgBool 26535c4bbdfSmrgRROutputSetCrtcs(RROutputPtr output, RRCrtcPtr * crtcs, int numCrtcs) 26605b261ecSmrg{ 26735c4bbdfSmrg RRCrtcPtr *newCrtcs; 26835c4bbdfSmrg int i; 26935c4bbdfSmrg 27035c4bbdfSmrg if (numCrtcs == output->numCrtcs) { 27135c4bbdfSmrg for (i = 0; i < numCrtcs; i++) 27235c4bbdfSmrg if (output->crtcs[i] != crtcs[i]) 27335c4bbdfSmrg break; 27435c4bbdfSmrg if (i == numCrtcs) 27535c4bbdfSmrg return TRUE; 27605b261ecSmrg } 27735c4bbdfSmrg if (numCrtcs) { 27835c4bbdfSmrg newCrtcs = xallocarray(numCrtcs, sizeof(RRCrtcPtr)); 27935c4bbdfSmrg if (!newCrtcs) 28035c4bbdfSmrg return FALSE; 28105b261ecSmrg } 28205b261ecSmrg else 28335c4bbdfSmrg newCrtcs = NULL; 2846747b715Smrg free(output->crtcs); 28535c4bbdfSmrg memcpy(newCrtcs, crtcs, numCrtcs * sizeof(RRCrtcPtr)); 28605b261ecSmrg output->crtcs = newCrtcs; 28705b261ecSmrg output->numCrtcs = numCrtcs; 28835c4bbdfSmrg RROutputChanged(output, TRUE); 28905b261ecSmrg return TRUE; 29005b261ecSmrg} 29105b261ecSmrg 29205b261ecSmrgBool 29335c4bbdfSmrgRROutputSetConnection(RROutputPtr output, CARD8 connection) 29405b261ecSmrg{ 29505b261ecSmrg if (output->connection == connection) 29635c4bbdfSmrg return TRUE; 29705b261ecSmrg output->connection = connection; 29835c4bbdfSmrg RROutputChanged(output, TRUE); 29905b261ecSmrg return TRUE; 30005b261ecSmrg} 30105b261ecSmrg 30205b261ecSmrgBool 30335c4bbdfSmrgRROutputSetSubpixelOrder(RROutputPtr output, int subpixelOrder) 30405b261ecSmrg{ 30505b261ecSmrg if (output->subpixelOrder == subpixelOrder) 30635c4bbdfSmrg return TRUE; 30705b261ecSmrg 30805b261ecSmrg output->subpixelOrder = subpixelOrder; 30935c4bbdfSmrg RROutputChanged(output, FALSE); 31005b261ecSmrg return TRUE; 31105b261ecSmrg} 31205b261ecSmrg 31305b261ecSmrgBool 31435c4bbdfSmrgRROutputSetPhysicalSize(RROutputPtr output, int mmWidth, int mmHeight) 31505b261ecSmrg{ 31605b261ecSmrg if (output->mmWidth == mmWidth && output->mmHeight == mmHeight) 31735c4bbdfSmrg return TRUE; 31805b261ecSmrg output->mmWidth = mmWidth; 31905b261ecSmrg output->mmHeight = mmHeight; 32035c4bbdfSmrg RROutputChanged(output, FALSE); 32105b261ecSmrg return TRUE; 32205b261ecSmrg} 32305b261ecSmrg 3241b5d61b8SmrgBool 3251b5d61b8SmrgRROutputSetNonDesktop(RROutputPtr output, Bool nonDesktop) 3261b5d61b8Smrg{ 3271b5d61b8Smrg const char *nonDesktopStr = RR_PROPERTY_NON_DESKTOP; 3281b5d61b8Smrg Atom nonDesktopProp = MakeAtom(nonDesktopStr, strlen(nonDesktopStr), TRUE); 3291b5d61b8Smrg uint32_t value = nonDesktop ? 1 : 0; 3301b5d61b8Smrg 3311b5d61b8Smrg if (nonDesktopProp == None || nonDesktopProp == BAD_RESOURCE) 3321b5d61b8Smrg return FALSE; 3331b5d61b8Smrg 3341b5d61b8Smrg return RRChangeOutputProperty(output, nonDesktopProp, XA_INTEGER, 32, 3351b5d61b8Smrg PropModeReplace, 1, &value, TRUE, FALSE) == Success; 3361b5d61b8Smrg} 3371b5d61b8Smrg 33805b261ecSmrgvoid 33905b261ecSmrgRRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output) 34005b261ecSmrg{ 34105b261ecSmrg ScreenPtr pScreen = pWin->drawable.pScreen; 34235c4bbdfSmrg 34335c4bbdfSmrg rrScrPriv(pScreen); 34435c4bbdfSmrg RRCrtcPtr crtc = output->crtc; 34535c4bbdfSmrg RRModePtr mode = crtc ? crtc->mode : NULL; 34635c4bbdfSmrg 34735c4bbdfSmrg xRROutputChangeNotifyEvent oe = { 34835c4bbdfSmrg .type = RRNotify + RREventBase, 34935c4bbdfSmrg .subCode = RRNotify_OutputChange, 35035c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds, 35135c4bbdfSmrg .configTimestamp = pScrPriv->lastConfigTime.milliseconds, 35235c4bbdfSmrg .window = pWin->drawable.id, 35335c4bbdfSmrg .output = output->id, 35435c4bbdfSmrg .crtc = crtc ? crtc->id : None, 35535c4bbdfSmrg .mode = mode ? mode->mode.id : None, 35635c4bbdfSmrg .rotation = crtc ? crtc->rotation : RR_Rotate_0, 3571b5d61b8Smrg .connection = output->nonDesktop ? RR_Disconnected : output->connection, 35835c4bbdfSmrg .subpixelOrder = output->subpixelOrder 35935c4bbdfSmrg }; 36035c4bbdfSmrg WriteEventsToClient(client, 1, (xEvent *) &oe); 36105b261ecSmrg} 36205b261ecSmrg 36305b261ecSmrg/* 36405b261ecSmrg * Destroy a Output at shutdown 36505b261ecSmrg */ 36605b261ecSmrgvoid 36735c4bbdfSmrgRROutputDestroy(RROutputPtr output) 36805b261ecSmrg{ 36935c4bbdfSmrg FreeResource(output->id, 0); 37005b261ecSmrg} 37105b261ecSmrg 37205b261ecSmrgstatic int 37335c4bbdfSmrgRROutputDestroyResource(void *value, XID pid) 37405b261ecSmrg{ 37535c4bbdfSmrg RROutputPtr output = (RROutputPtr) value; 37635c4bbdfSmrg ScreenPtr pScreen = output->pScreen; 37735c4bbdfSmrg int m; 37835c4bbdfSmrg 37935c4bbdfSmrg if (pScreen) { 38035c4bbdfSmrg rrScrPriv(pScreen); 38135c4bbdfSmrg int i; 3821b5d61b8Smrg RRLeasePtr lease, next; 3831b5d61b8Smrg 3841b5d61b8Smrg xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) { 3851b5d61b8Smrg int o; 3861b5d61b8Smrg for (o = 0; o < lease->numOutputs; o++) { 3871b5d61b8Smrg if (lease->outputs[o] == output) { 3881b5d61b8Smrg RRTerminateLease(lease); 3891b5d61b8Smrg break; 3901b5d61b8Smrg } 3911b5d61b8Smrg } 3921b5d61b8Smrg } 39335c4bbdfSmrg 39435c4bbdfSmrg if (pScrPriv->primaryOutput == output) 39535c4bbdfSmrg pScrPriv->primaryOutput = NULL; 39635c4bbdfSmrg 39735c4bbdfSmrg for (i = 0; i < pScrPriv->numOutputs; i++) { 39835c4bbdfSmrg if (pScrPriv->outputs[i] == output) { 39935c4bbdfSmrg memmove(pScrPriv->outputs + i, pScrPriv->outputs + i + 1, 40035c4bbdfSmrg (pScrPriv->numOutputs - (i + 1)) * sizeof(RROutputPtr)); 40135c4bbdfSmrg --pScrPriv->numOutputs; 40235c4bbdfSmrg break; 40335c4bbdfSmrg } 40435c4bbdfSmrg } 40535c4bbdfSmrg 40635c4bbdfSmrg RRResourcesChanged(pScreen); 40705b261ecSmrg } 40835c4bbdfSmrg if (output->modes) { 40935c4bbdfSmrg for (m = 0; m < output->numModes; m++) 41035c4bbdfSmrg RRModeDestroy(output->modes[m]); 41135c4bbdfSmrg free(output->modes); 41205b261ecSmrg } 41335c4bbdfSmrg 41405b261ecSmrg for (m = 0; m < output->numUserModes; m++) 41535c4bbdfSmrg RRModeDestroy(output->userModes[m]); 4166747b715Smrg free(output->userModes); 41705b261ecSmrg 4186747b715Smrg free(output->crtcs); 4196747b715Smrg free(output->clones); 42035c4bbdfSmrg RRDeleteAllOutputProperties(output); 4216747b715Smrg free(output); 42205b261ecSmrg return 1; 42305b261ecSmrg} 42405b261ecSmrg 42505b261ecSmrg/* 42605b261ecSmrg * Initialize output type 42705b261ecSmrg */ 42805b261ecSmrgBool 42935c4bbdfSmrgRROutputInit(void) 43005b261ecSmrg{ 43135c4bbdfSmrg RROutputType = CreateNewResourceType(RROutputDestroyResource, "OUTPUT"); 43205b261ecSmrg if (!RROutputType) 43335c4bbdfSmrg return FALSE; 4346747b715Smrg 43505b261ecSmrg return TRUE; 43605b261ecSmrg} 43705b261ecSmrg 4386747b715Smrg/* 4396747b715Smrg * Initialize output type error value 4406747b715Smrg */ 4416747b715Smrgvoid 4426747b715SmrgRROutputInitErrorValue(void) 4436747b715Smrg{ 4446747b715Smrg SetResourceTypeErrorValue(RROutputType, RRErrorBase + BadRROutput); 4456747b715Smrg} 4466747b715Smrg 44705b261ecSmrg#define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32) 4484642e01fSmrg 44905b261ecSmrgint 45035c4bbdfSmrgProcRRGetOutputInfo(ClientPtr client) 45105b261ecSmrg{ 45205b261ecSmrg REQUEST(xRRGetOutputInfoReq); 45335c4bbdfSmrg xRRGetOutputInfoReply rep; 45435c4bbdfSmrg RROutputPtr output; 45535c4bbdfSmrg CARD8 *extra; 45635c4bbdfSmrg unsigned long extraLen; 45735c4bbdfSmrg ScreenPtr pScreen; 45835c4bbdfSmrg rrScrPrivPtr pScrPriv; 45935c4bbdfSmrg RRCrtc *crtcs; 46035c4bbdfSmrg RRMode *modes; 46135c4bbdfSmrg RROutput *clones; 46235c4bbdfSmrg char *name; 46335c4bbdfSmrg int i; 4641b5d61b8Smrg Bool leased; 46535c4bbdfSmrg 46605b261ecSmrg REQUEST_SIZE_MATCH(xRRGetOutputInfoReq); 4676747b715Smrg VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 46805b261ecSmrg 4691b5d61b8Smrg leased = RROutputIsLeased(output); 4701b5d61b8Smrg 47105b261ecSmrg pScreen = output->pScreen; 47205b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 47305b261ecSmrg 4741b5d61b8Smrg if (leased) { 4751b5d61b8Smrg rep = (xRRGetOutputInfoReply) { 4761b5d61b8Smrg .type = X_Reply, 4771b5d61b8Smrg .status = RRSetConfigSuccess, 4781b5d61b8Smrg .sequenceNumber = client->sequence, 4791b5d61b8Smrg .length = bytes_to_int32(OutputInfoExtra), 4801b5d61b8Smrg .timestamp = pScrPriv->lastSetTime.milliseconds, 4811b5d61b8Smrg .crtc = None, 4821b5d61b8Smrg .mmWidth = 0, 4831b5d61b8Smrg .mmHeight = 0, 4841b5d61b8Smrg .connection = RR_Disconnected, 4851b5d61b8Smrg .subpixelOrder = SubPixelUnknown, 4861b5d61b8Smrg .nCrtcs = 0, 4871b5d61b8Smrg .nModes = 0, 4881b5d61b8Smrg .nPreferred = 0, 4891b5d61b8Smrg .nClones = 0, 4901b5d61b8Smrg .nameLength = output->nameLength 4911b5d61b8Smrg }; 4921b5d61b8Smrg extraLen = bytes_to_int32(rep.nameLength) << 2; 4931b5d61b8Smrg if (extraLen) { 4941b5d61b8Smrg rep.length += bytes_to_int32(extraLen); 4951b5d61b8Smrg extra = calloc(1, extraLen); 4961b5d61b8Smrg if (!extra) 4971b5d61b8Smrg return BadAlloc; 4981b5d61b8Smrg } 4991b5d61b8Smrg else 5001b5d61b8Smrg extra = NULL; 5011b5d61b8Smrg 5021b5d61b8Smrg name = (char *) extra; 5031b5d61b8Smrg } else { 5041b5d61b8Smrg rep = (xRRGetOutputInfoReply) { 5051b5d61b8Smrg .type = X_Reply, 5061b5d61b8Smrg .status = RRSetConfigSuccess, 5071b5d61b8Smrg .sequenceNumber = client->sequence, 5081b5d61b8Smrg .length = bytes_to_int32(OutputInfoExtra), 5091b5d61b8Smrg .timestamp = pScrPriv->lastSetTime.milliseconds, 5101b5d61b8Smrg .crtc = output->crtc ? output->crtc->id : None, 5111b5d61b8Smrg .mmWidth = output->mmWidth, 5121b5d61b8Smrg .mmHeight = output->mmHeight, 5131b5d61b8Smrg .connection = output->nonDesktop ? RR_Disconnected : output->connection, 5141b5d61b8Smrg .subpixelOrder = output->subpixelOrder, 5151b5d61b8Smrg .nCrtcs = output->numCrtcs, 5161b5d61b8Smrg .nModes = output->numModes + output->numUserModes, 5171b5d61b8Smrg .nPreferred = output->numPreferred, 5181b5d61b8Smrg .nClones = output->numClones, 5191b5d61b8Smrg .nameLength = output->nameLength 5201b5d61b8Smrg }; 5211b5d61b8Smrg extraLen = ((output->numCrtcs + 5221b5d61b8Smrg output->numModes + output->numUserModes + 5231b5d61b8Smrg output->numClones + bytes_to_int32(rep.nameLength)) << 2); 5241b5d61b8Smrg 5251b5d61b8Smrg if (extraLen) { 5261b5d61b8Smrg rep.length += bytes_to_int32(extraLen); 5271b5d61b8Smrg extra = calloc(1, extraLen); 5281b5d61b8Smrg if (!extra) 5291b5d61b8Smrg return BadAlloc; 5301b5d61b8Smrg } 5311b5d61b8Smrg else 5321b5d61b8Smrg extra = NULL; 53305b261ecSmrg 5341b5d61b8Smrg crtcs = (RRCrtc *) extra; 5351b5d61b8Smrg modes = (RRMode *) (crtcs + output->numCrtcs); 5361b5d61b8Smrg clones = (RROutput *) (modes + output->numModes + output->numUserModes); 5371b5d61b8Smrg name = (char *) (clones + output->numClones); 53835c4bbdfSmrg 5391b5d61b8Smrg for (i = 0; i < output->numCrtcs; i++) { 5401b5d61b8Smrg crtcs[i] = output->crtcs[i]->id; 5411b5d61b8Smrg if (client->swapped) 5421b5d61b8Smrg swapl(&crtcs[i]); 5431b5d61b8Smrg } 5441b5d61b8Smrg for (i = 0; i < output->numModes + output->numUserModes; i++) { 5451b5d61b8Smrg if (i < output->numModes) 5461b5d61b8Smrg modes[i] = output->modes[i]->mode.id; 5471b5d61b8Smrg else 5481b5d61b8Smrg modes[i] = output->userModes[i - output->numModes]->mode.id; 5491b5d61b8Smrg if (client->swapped) 5501b5d61b8Smrg swapl(&modes[i]); 5511b5d61b8Smrg } 5521b5d61b8Smrg for (i = 0; i < output->numClones; i++) { 5531b5d61b8Smrg clones[i] = output->clones[i]->id; 5541b5d61b8Smrg if (client->swapped) 5551b5d61b8Smrg swapl(&clones[i]); 5561b5d61b8Smrg } 55705b261ecSmrg } 55835c4bbdfSmrg memcpy(name, output->name, output->nameLength); 55905b261ecSmrg if (client->swapped) { 56035c4bbdfSmrg swaps(&rep.sequenceNumber); 56135c4bbdfSmrg swapl(&rep.length); 56235c4bbdfSmrg swapl(&rep.timestamp); 56335c4bbdfSmrg swapl(&rep.crtc); 56435c4bbdfSmrg swapl(&rep.mmWidth); 56535c4bbdfSmrg swapl(&rep.mmHeight); 56635c4bbdfSmrg swaps(&rep.nCrtcs); 56735c4bbdfSmrg swaps(&rep.nModes); 56835c4bbdfSmrg swaps(&rep.nPreferred); 56935c4bbdfSmrg swaps(&rep.nClones); 57035c4bbdfSmrg swaps(&rep.nameLength); 57105b261ecSmrg } 57235c4bbdfSmrg WriteToClient(client, sizeof(xRRGetOutputInfoReply), &rep); 57335c4bbdfSmrg if (extraLen) { 57435c4bbdfSmrg WriteToClient(client, extraLen, extra); 57535c4bbdfSmrg free(extra); 57605b261ecSmrg } 57735c4bbdfSmrg 5786747b715Smrg return Success; 57905b261ecSmrg} 5804642e01fSmrg 5816747b715Smrgstatic void 58235c4bbdfSmrgRRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv, RROutputPtr output) 5834642e01fSmrg{ 5844642e01fSmrg if (pScrPriv->primaryOutput == output) 58535c4bbdfSmrg return; 5864642e01fSmrg 5874642e01fSmrg /* clear the old primary */ 5884642e01fSmrg if (pScrPriv->primaryOutput) { 58935c4bbdfSmrg RROutputChanged(pScrPriv->primaryOutput, 0); 59035c4bbdfSmrg pScrPriv->primaryOutput = NULL; 5914642e01fSmrg } 5924642e01fSmrg 5934642e01fSmrg /* set the new primary */ 5944642e01fSmrg if (output) { 59535c4bbdfSmrg pScrPriv->primaryOutput = output; 59635c4bbdfSmrg RROutputChanged(output, 0); 5974642e01fSmrg } 5984642e01fSmrg 5994642e01fSmrg pScrPriv->layoutChanged = TRUE; 6004642e01fSmrg 6014642e01fSmrg RRTellChanged(pScreen); 6024642e01fSmrg} 6034642e01fSmrg 6044642e01fSmrgint 6054642e01fSmrgProcRRSetOutputPrimary(ClientPtr client) 6064642e01fSmrg{ 6074642e01fSmrg REQUEST(xRRSetOutputPrimaryReq); 6084642e01fSmrg RROutputPtr output = NULL; 6094642e01fSmrg WindowPtr pWin; 6104642e01fSmrg rrScrPrivPtr pScrPriv; 61135c4bbdfSmrg int ret; 612ed6184dfSmrg ScreenPtr secondary; 6134642e01fSmrg 6144642e01fSmrg REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq); 6154642e01fSmrg 61635c4bbdfSmrg ret = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 61735c4bbdfSmrg if (ret != Success) 61835c4bbdfSmrg return ret; 6194642e01fSmrg 6204642e01fSmrg if (stuff->output) { 62135c4bbdfSmrg VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess); 62235c4bbdfSmrg 6231b5d61b8Smrg if (RROutputIsLeased(output)) 6241b5d61b8Smrg return BadAccess; 6251b5d61b8Smrg 62635c4bbdfSmrg if (!output->pScreen->isGPU && output->pScreen != pWin->drawable.pScreen) { 62735c4bbdfSmrg client->errorValue = stuff->window; 62835c4bbdfSmrg return BadMatch; 62935c4bbdfSmrg } 630ed6184dfSmrg if (output->pScreen->isGPU && output->pScreen->current_primary != pWin->drawable.pScreen) { 63135c4bbdfSmrg client->errorValue = stuff->window; 63235c4bbdfSmrg return BadMatch; 63335c4bbdfSmrg } 6344642e01fSmrg } 6354642e01fSmrg 6364642e01fSmrg pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); 63735c4bbdfSmrg if (pScrPriv) 63835c4bbdfSmrg { 63935c4bbdfSmrg RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output); 64035c4bbdfSmrg 641ed6184dfSmrg xorg_list_for_each_entry(secondary, 642ed6184dfSmrg &pWin->drawable.pScreen->secondary_list, 643ed6184dfSmrg secondary_head) { 644ed6184dfSmrg if (secondary->is_output_secondary) 645ed6184dfSmrg RRSetPrimaryOutput(secondary, rrGetScrPriv(secondary), output); 64635c4bbdfSmrg } 64735c4bbdfSmrg } 6484642e01fSmrg 6496747b715Smrg return Success; 6504642e01fSmrg} 6514642e01fSmrg 6524642e01fSmrgint 6534642e01fSmrgProcRRGetOutputPrimary(ClientPtr client) 6544642e01fSmrg{ 6554642e01fSmrg REQUEST(xRRGetOutputPrimaryReq); 6564642e01fSmrg WindowPtr pWin; 6574642e01fSmrg rrScrPrivPtr pScrPriv; 6584642e01fSmrg xRRGetOutputPrimaryReply rep; 6594642e01fSmrg RROutputPtr primary = NULL; 6606747b715Smrg int rc; 6614642e01fSmrg 6624642e01fSmrg REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq); 6634642e01fSmrg 6646747b715Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 6656747b715Smrg if (rc != Success) 66635c4bbdfSmrg return rc; 6674642e01fSmrg 6684642e01fSmrg pScrPriv = rrGetScrPriv(pWin->drawable.pScreen); 6694642e01fSmrg if (pScrPriv) 67035c4bbdfSmrg primary = pScrPriv->primaryOutput; 6714642e01fSmrg 67235c4bbdfSmrg rep = (xRRGetOutputPrimaryReply) { 67335c4bbdfSmrg .type = X_Reply, 67435c4bbdfSmrg .sequenceNumber = client->sequence, 67535c4bbdfSmrg .output = primary ? primary->id : None 67635c4bbdfSmrg }; 6774642e01fSmrg 6784642e01fSmrg if (client->swapped) { 67935c4bbdfSmrg swaps(&rep.sequenceNumber); 68035c4bbdfSmrg swapl(&rep.output); 6814642e01fSmrg } 6824642e01fSmrg 6834642e01fSmrg WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep); 6844642e01fSmrg 6856747b715Smrg return Success; 6864642e01fSmrg} 687