105b261ecSmrg/* 205b261ecSmrg * Copyright © 2006 Keith Packard 305b261ecSmrg * 405b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 505b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 605b261ecSmrg * the above copyright notice appear in all copies and that both that copyright 705b261ecSmrg * notice and this permission notice appear in supporting documentation, and 805b261ecSmrg * that the name of the copyright holders not be used in advertising or 905b261ecSmrg * publicity pertaining to distribution of the software without specific, 1005b261ecSmrg * written prior permission. The copyright holders make no representations 1105b261ecSmrg * about the suitability of this software for any purpose. It is provided "as 1205b261ecSmrg * is" without express or implied warranty. 1305b261ecSmrg * 1405b261ecSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1505b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1605b261ecSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1705b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1805b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1905b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2005b261ecSmrg * OF THIS SOFTWARE. 2105b261ecSmrg */ 2205b261ecSmrg 2305b261ecSmrg#include "randrstr.h" 2405b261ecSmrg 2505b261ecSmrgstatic CARD16 2635c4bbdfSmrg RR10CurrentSizeID(ScreenPtr pScreen); 2705b261ecSmrg 2805b261ecSmrg/* 2905b261ecSmrg * Edit connection information block so that new clients 3005b261ecSmrg * see the current screen size on connect 3105b261ecSmrg */ 3205b261ecSmrgstatic void 3335c4bbdfSmrgRREditConnectionInfo(ScreenPtr pScreen) 3405b261ecSmrg{ 3535c4bbdfSmrg xConnSetup *connSetup; 3635c4bbdfSmrg char *vendor; 3735c4bbdfSmrg xPixmapFormat *formats; 3835c4bbdfSmrg xWindowRoot *root; 3935c4bbdfSmrg xDepth *depth; 4035c4bbdfSmrg xVisualType *visual; 4135c4bbdfSmrg int screen = 0; 4235c4bbdfSmrg int d; 4305b261ecSmrg 441b5d61b8Smrg if (ConnectionInfo == NULL) 451b5d61b8Smrg return; 461b5d61b8Smrg 4705b261ecSmrg connSetup = (xConnSetup *) ConnectionInfo; 4835c4bbdfSmrg vendor = (char *) connSetup + sizeof(xConnSetup); 4905b261ecSmrg formats = (xPixmapFormat *) ((char *) vendor + 5035c4bbdfSmrg pad_to_int32(connSetup->nbytesVendor)); 5105b261ecSmrg root = (xWindowRoot *) ((char *) formats + 5235c4bbdfSmrg sizeof(xPixmapFormat) * 5335c4bbdfSmrg screenInfo.numPixmapFormats); 5435c4bbdfSmrg while (screen != pScreen->myNum) { 5535c4bbdfSmrg depth = (xDepth *) ((char *) root + sizeof(xWindowRoot)); 5635c4bbdfSmrg for (d = 0; d < root->nDepths; d++) { 5735c4bbdfSmrg visual = (xVisualType *) ((char *) depth + sizeof(xDepth)); 5835c4bbdfSmrg depth = (xDepth *) ((char *) visual + 5935c4bbdfSmrg depth->nVisuals * sizeof(xVisualType)); 6035c4bbdfSmrg } 6135c4bbdfSmrg root = (xWindowRoot *) ((char *) depth); 6235c4bbdfSmrg screen++; 6305b261ecSmrg } 6405b261ecSmrg root->pixWidth = pScreen->width; 6505b261ecSmrg root->pixHeight = pScreen->height; 6605b261ecSmrg root->mmWidth = pScreen->mmWidth; 6705b261ecSmrg root->mmHeight = pScreen->mmHeight; 6805b261ecSmrg} 6905b261ecSmrg 7005b261ecSmrgvoid 7135c4bbdfSmrgRRSendConfigNotify(ScreenPtr pScreen) 7205b261ecSmrg{ 7335c4bbdfSmrg WindowPtr pWin = pScreen->root; 7435c4bbdfSmrg xEvent event = { 7535c4bbdfSmrg .u.configureNotify.window = pWin->drawable.id, 7635c4bbdfSmrg .u.configureNotify.aboveSibling = None, 7735c4bbdfSmrg .u.configureNotify.x = 0, 7835c4bbdfSmrg .u.configureNotify.y = 0, 7905b261ecSmrg 8005b261ecSmrg /* XXX xinerama stuff ? */ 8135c4bbdfSmrg 8235c4bbdfSmrg .u.configureNotify.width = pWin->drawable.width, 8335c4bbdfSmrg .u.configureNotify.height = pWin->drawable.height, 8435c4bbdfSmrg .u.configureNotify.borderWidth = wBorderWidth(pWin), 8535c4bbdfSmrg .u.configureNotify.override = pWin->overrideRedirect 8635c4bbdfSmrg }; 8735c4bbdfSmrg event.u.u.type = ConfigureNotify; 8805b261ecSmrg DeliverEvents(pWin, &event, 1, NullWindow); 8905b261ecSmrg} 9005b261ecSmrg 9105b261ecSmrgvoid 9235c4bbdfSmrgRRDeliverScreenEvent(ClientPtr client, WindowPtr pWin, ScreenPtr pScreen) 9305b261ecSmrg{ 9435c4bbdfSmrg rrScrPriv(pScreen); 9535c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL; 9635c4bbdfSmrg WindowPtr pRoot = pScreen->root; 9735c4bbdfSmrg 9835c4bbdfSmrg xRRScreenChangeNotifyEvent se = { 9935c4bbdfSmrg .type = RRScreenChangeNotify + RREventBase, 10035c4bbdfSmrg .rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0), 10135c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds, 10235c4bbdfSmrg .configTimestamp = pScrPriv->lastConfigTime.milliseconds, 10335c4bbdfSmrg .root = pRoot->drawable.id, 10435c4bbdfSmrg .window = pWin->drawable.id, 10535c4bbdfSmrg .subpixelOrder = PictureGetSubpixelOrder(pScreen), 10635c4bbdfSmrg 10735c4bbdfSmrg .sizeID = RR10CurrentSizeID(pScreen) 10835c4bbdfSmrg }; 10905b261ecSmrg 11005b261ecSmrg if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) { 11135c4bbdfSmrg se.widthInPixels = pScreen->height; 11235c4bbdfSmrg se.heightInPixels = pScreen->width; 11335c4bbdfSmrg se.widthInMillimeters = pScreen->mmHeight; 11435c4bbdfSmrg se.heightInMillimeters = pScreen->mmWidth; 11535c4bbdfSmrg } 11635c4bbdfSmrg else { 11735c4bbdfSmrg se.widthInPixels = pScreen->width; 11835c4bbdfSmrg se.heightInPixels = pScreen->height; 11935c4bbdfSmrg se.widthInMillimeters = pScreen->mmWidth; 12035c4bbdfSmrg se.heightInMillimeters = pScreen->mmHeight; 12135c4bbdfSmrg } 12235c4bbdfSmrg 12335c4bbdfSmrg WriteEventsToClient(client, 1, (xEvent *) &se); 12405b261ecSmrg} 12505b261ecSmrg 12605b261ecSmrg/* 12705b261ecSmrg * Notify the extension that the screen size has been changed. 12805b261ecSmrg * The driver is responsible for calling this whenever it has changed 12905b261ecSmrg * the size of the screen 13005b261ecSmrg */ 13105b261ecSmrgvoid 13235c4bbdfSmrgRRScreenSizeNotify(ScreenPtr pScreen) 13305b261ecSmrg{ 13405b261ecSmrg rrScrPriv(pScreen); 13505b261ecSmrg /* 13605b261ecSmrg * Deliver ConfigureNotify events when root changes 13705b261ecSmrg * pixel size 13805b261ecSmrg */ 13905b261ecSmrg if (pScrPriv->width == pScreen->width && 14035c4bbdfSmrg pScrPriv->height == pScreen->height && 14135c4bbdfSmrg pScrPriv->mmWidth == pScreen->mmWidth && 14235c4bbdfSmrg pScrPriv->mmHeight == pScreen->mmHeight) 14335c4bbdfSmrg return; 14435c4bbdfSmrg 14505b261ecSmrg pScrPriv->width = pScreen->width; 14605b261ecSmrg pScrPriv->height = pScreen->height; 14705b261ecSmrg pScrPriv->mmWidth = pScreen->mmWidth; 14805b261ecSmrg pScrPriv->mmHeight = pScreen->mmHeight; 14935c4bbdfSmrg RRSetChanged(pScreen); 15005b261ecSmrg/* pScrPriv->sizeChanged = TRUE; */ 15105b261ecSmrg 15235c4bbdfSmrg RRTellChanged(pScreen); 15335c4bbdfSmrg RRSendConfigNotify(pScreen); 15435c4bbdfSmrg RREditConnectionInfo(pScreen); 15535c4bbdfSmrg 15635c4bbdfSmrg RRPointerScreenConfigured(pScreen); 15705b261ecSmrg /* 15805b261ecSmrg * Fix pointer bounds and location 15905b261ecSmrg */ 16035c4bbdfSmrg ScreenRestructured(pScreen); 16105b261ecSmrg} 16205b261ecSmrg 16305b261ecSmrg/* 16405b261ecSmrg * Request that the screen be resized 16505b261ecSmrg */ 16605b261ecSmrgBool 16735c4bbdfSmrgRRScreenSizeSet(ScreenPtr pScreen, 16835c4bbdfSmrg CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight) 16905b261ecSmrg{ 17005b261ecSmrg rrScrPriv(pScreen); 17105b261ecSmrg 17205b261ecSmrg#if RANDR_12_INTERFACE 17335c4bbdfSmrg if (pScrPriv->rrScreenSetSize) { 17435c4bbdfSmrg return (*pScrPriv->rrScreenSetSize) (pScreen, 17535c4bbdfSmrg width, height, mmWidth, mmHeight); 17605b261ecSmrg } 17705b261ecSmrg#endif 17805b261ecSmrg#if RANDR_10_INTERFACE 17935c4bbdfSmrg if (pScrPriv->rrSetConfig) { 18035c4bbdfSmrg return TRUE; /* can't set size separately */ 18105b261ecSmrg } 18205b261ecSmrg#endif 18305b261ecSmrg return FALSE; 18405b261ecSmrg} 18505b261ecSmrg 18605b261ecSmrg/* 18705b261ecSmrg * Retrieve valid screen size range 18805b261ecSmrg */ 1896747b715Smrgint 19035c4bbdfSmrgProcRRGetScreenSizeRange(ClientPtr client) 19105b261ecSmrg{ 19205b261ecSmrg REQUEST(xRRGetScreenSizeRangeReq); 19335c4bbdfSmrg xRRGetScreenSizeRangeReply rep; 19435c4bbdfSmrg WindowPtr pWin; 19535c4bbdfSmrg ScreenPtr pScreen; 19635c4bbdfSmrg rrScrPrivPtr pScrPriv; 19735c4bbdfSmrg int rc; 19835c4bbdfSmrg 19935c4bbdfSmrg REQUEST_SIZE_MATCH(xRRGetScreenSizeRangeReq); 2006747b715Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 20105b261ecSmrg if (rc != Success) 20235c4bbdfSmrg return rc; 20305b261ecSmrg 20405b261ecSmrg pScreen = pWin->drawable.pScreen; 20505b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 20635c4bbdfSmrg 20735c4bbdfSmrg rep = (xRRGetScreenSizeRangeReply) { 20835c4bbdfSmrg .type = X_Reply, 20935c4bbdfSmrg .pad = 0, 21035c4bbdfSmrg .sequenceNumber = client->sequence, 21135c4bbdfSmrg .length = 0 21235c4bbdfSmrg }; 21335c4bbdfSmrg 21435c4bbdfSmrg if (pScrPriv) { 21535c4bbdfSmrg if (!RRGetInfo(pScreen, FALSE)) 21635c4bbdfSmrg return BadAlloc; 21735c4bbdfSmrg rep.minWidth = pScrPriv->minWidth; 21835c4bbdfSmrg rep.minHeight = pScrPriv->minHeight; 21935c4bbdfSmrg rep.maxWidth = pScrPriv->maxWidth; 22035c4bbdfSmrg rep.maxHeight = pScrPriv->maxHeight; 22105b261ecSmrg } 22235c4bbdfSmrg else { 22335c4bbdfSmrg rep.maxWidth = rep.minWidth = pScreen->width; 22435c4bbdfSmrg rep.maxHeight = rep.minHeight = pScreen->height; 22535c4bbdfSmrg } 22635c4bbdfSmrg if (client->swapped) { 22735c4bbdfSmrg swaps(&rep.sequenceNumber); 22835c4bbdfSmrg swapl(&rep.length); 22935c4bbdfSmrg swaps(&rep.minWidth); 23035c4bbdfSmrg swaps(&rep.minHeight); 23135c4bbdfSmrg swaps(&rep.maxWidth); 23235c4bbdfSmrg swaps(&rep.maxHeight); 23335c4bbdfSmrg } 23435c4bbdfSmrg WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), &rep); 2356747b715Smrg return Success; 23605b261ecSmrg} 23705b261ecSmrg 23805b261ecSmrgint 23935c4bbdfSmrgProcRRSetScreenSize(ClientPtr client) 24005b261ecSmrg{ 24105b261ecSmrg REQUEST(xRRSetScreenSizeReq); 24235c4bbdfSmrg WindowPtr pWin; 24335c4bbdfSmrg ScreenPtr pScreen; 24435c4bbdfSmrg rrScrPrivPtr pScrPriv; 24535c4bbdfSmrg int i, rc; 24635c4bbdfSmrg 24705b261ecSmrg REQUEST_SIZE_MATCH(xRRSetScreenSizeReq); 2486747b715Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 24905b261ecSmrg if (rc != Success) 25035c4bbdfSmrg return rc; 25105b261ecSmrg 25205b261ecSmrg pScreen = pWin->drawable.pScreen; 25305b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 25435c4bbdfSmrg if (!pScrPriv) 25535c4bbdfSmrg return BadMatch; 25635c4bbdfSmrg 25735c4bbdfSmrg if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width) { 25835c4bbdfSmrg client->errorValue = stuff->width; 25935c4bbdfSmrg return BadValue; 26035c4bbdfSmrg } 26135c4bbdfSmrg if (stuff->height < pScrPriv->minHeight || 26235c4bbdfSmrg pScrPriv->maxHeight < stuff->height) { 26335c4bbdfSmrg client->errorValue = stuff->height; 26435c4bbdfSmrg return BadValue; 26535c4bbdfSmrg } 26635c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 26735c4bbdfSmrg RRCrtcPtr crtc = pScrPriv->crtcs[i]; 26835c4bbdfSmrg RRModePtr mode = crtc->mode; 26935c4bbdfSmrg 2701b5d61b8Smrg if (!RRCrtcIsLeased(crtc) && mode) { 27135c4bbdfSmrg int source_width = mode->mode.width; 27235c4bbdfSmrg int source_height = mode->mode.height; 27335c4bbdfSmrg Rotation rotation = crtc->rotation; 27435c4bbdfSmrg 2751b5d61b8Smrg if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 27635c4bbdfSmrg source_width = mode->mode.height; 27735c4bbdfSmrg source_height = mode->mode.width; 27835c4bbdfSmrg } 27935c4bbdfSmrg 28035c4bbdfSmrg if (crtc->x + source_width > stuff->width || 28135c4bbdfSmrg crtc->y + source_height > stuff->height) 28235c4bbdfSmrg return BadMatch; 28335c4bbdfSmrg } 28435c4bbdfSmrg } 28535c4bbdfSmrg if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0) { 28635c4bbdfSmrg client->errorValue = 0; 28735c4bbdfSmrg return BadValue; 28835c4bbdfSmrg } 28935c4bbdfSmrg if (!RRScreenSizeSet(pScreen, 29035c4bbdfSmrg stuff->width, stuff->height, 29135c4bbdfSmrg stuff->widthInMillimeters, 29235c4bbdfSmrg stuff->heightInMillimeters)) { 29335c4bbdfSmrg return BadMatch; 29435c4bbdfSmrg } 29535c4bbdfSmrg return Success; 29635c4bbdfSmrg} 29735c4bbdfSmrg 29835c4bbdfSmrg 29935c4bbdfSmrg#define update_totals(gpuscreen, pScrPriv) do { \ 30035c4bbdfSmrg total_crtcs += pScrPriv->numCrtcs; \ 30135c4bbdfSmrg total_outputs += pScrPriv->numOutputs; \ 30235c4bbdfSmrg modes = RRModesForScreen(gpuscreen, &num_modes); \ 30335c4bbdfSmrg if (!modes) \ 30435c4bbdfSmrg return BadAlloc; \ 30535c4bbdfSmrg for (j = 0; j < num_modes; j++) \ 30635c4bbdfSmrg total_name_len += modes[j]->mode.nameLength; \ 30735c4bbdfSmrg total_modes += num_modes; \ 30835c4bbdfSmrg free(modes); \ 30935c4bbdfSmrg} while(0) 31035c4bbdfSmrg 31135c4bbdfSmrgstatic inline void swap_modeinfos(xRRModeInfo *modeinfos, int i) 31235c4bbdfSmrg{ 31335c4bbdfSmrg swapl(&modeinfos[i].id); 31435c4bbdfSmrg swaps(&modeinfos[i].width); 31535c4bbdfSmrg swaps(&modeinfos[i].height); 31635c4bbdfSmrg swapl(&modeinfos[i].dotClock); 31735c4bbdfSmrg swaps(&modeinfos[i].hSyncStart); 31835c4bbdfSmrg swaps(&modeinfos[i].hSyncEnd); 31935c4bbdfSmrg swaps(&modeinfos[i].hTotal); 32035c4bbdfSmrg swaps(&modeinfos[i].hSkew); 32135c4bbdfSmrg swaps(&modeinfos[i].vSyncStart); 32235c4bbdfSmrg swaps(&modeinfos[i].vSyncEnd); 32335c4bbdfSmrg swaps(&modeinfos[i].vTotal); 32435c4bbdfSmrg swaps(&modeinfos[i].nameLength); 32535c4bbdfSmrg swapl(&modeinfos[i].modeFlags); 32635c4bbdfSmrg} 32735c4bbdfSmrg 32835c4bbdfSmrg#define update_arrays(gpuscreen, pScrPriv, primary_crtc, has_primary) do { \ 32935c4bbdfSmrg for (j = 0; j < pScrPriv->numCrtcs; j++) { \ 33035c4bbdfSmrg if (has_primary && \ 33135c4bbdfSmrg primary_crtc == pScrPriv->crtcs[j]) { \ 33235c4bbdfSmrg has_primary = 0; \ 33335c4bbdfSmrg continue; \ 33435c4bbdfSmrg }\ 33535c4bbdfSmrg crtcs[crtc_count] = pScrPriv->crtcs[j]->id; \ 33635c4bbdfSmrg if (client->swapped) \ 33735c4bbdfSmrg swapl(&crtcs[crtc_count]); \ 33835c4bbdfSmrg crtc_count++; \ 33935c4bbdfSmrg } \ 34035c4bbdfSmrg for (j = 0; j < pScrPriv->numOutputs; j++) { \ 34135c4bbdfSmrg outputs[output_count] = pScrPriv->outputs[j]->id; \ 34235c4bbdfSmrg if (client->swapped) \ 34335c4bbdfSmrg swapl(&outputs[output_count]); \ 34435c4bbdfSmrg output_count++; \ 34535c4bbdfSmrg } \ 34635c4bbdfSmrg { \ 34735c4bbdfSmrg RRModePtr mode; \ 34835c4bbdfSmrg modes = RRModesForScreen(gpuscreen, &num_modes); \ 34935c4bbdfSmrg for (j = 0; j < num_modes; j++) { \ 35035c4bbdfSmrg mode = modes[j]; \ 35135c4bbdfSmrg modeinfos[mode_count] = mode->mode; \ 35235c4bbdfSmrg if (client->swapped) { \ 35335c4bbdfSmrg swap_modeinfos(modeinfos, mode_count); \ 35435c4bbdfSmrg } \ 35535c4bbdfSmrg memcpy(names, mode->name, mode->mode.nameLength); \ 35635c4bbdfSmrg names += mode->mode.nameLength; \ 35735c4bbdfSmrg mode_count++; \ 35835c4bbdfSmrg } \ 35935c4bbdfSmrg free(modes); \ 36035c4bbdfSmrg } \ 36135c4bbdfSmrg } while (0) 36235c4bbdfSmrg 36335c4bbdfSmrgstatic int 36435c4bbdfSmrgrrGetMultiScreenResources(ClientPtr client, Bool query, ScreenPtr pScreen) 36535c4bbdfSmrg{ 36635c4bbdfSmrg int j; 36735c4bbdfSmrg int total_crtcs, total_outputs, total_modes, total_name_len; 36835c4bbdfSmrg int crtc_count, output_count, mode_count; 36935c4bbdfSmrg ScreenPtr iter; 37035c4bbdfSmrg rrScrPrivPtr pScrPriv; 37135c4bbdfSmrg int num_modes; 37235c4bbdfSmrg RRModePtr *modes; 37335c4bbdfSmrg xRRGetScreenResourcesReply rep; 37435c4bbdfSmrg unsigned long extraLen; 37535c4bbdfSmrg CARD8 *extra; 37635c4bbdfSmrg RRCrtc *crtcs; 37735c4bbdfSmrg RRCrtcPtr primary_crtc = NULL; 37835c4bbdfSmrg RROutput *outputs; 37935c4bbdfSmrg xRRModeInfo *modeinfos; 38035c4bbdfSmrg CARD8 *names; 38135c4bbdfSmrg int has_primary = 0; 38235c4bbdfSmrg 383ed6184dfSmrg /* we need to iterate all the GPU primarys and all their output secondarys */ 38435c4bbdfSmrg total_crtcs = 0; 38535c4bbdfSmrg total_outputs = 0; 38635c4bbdfSmrg total_modes = 0; 38735c4bbdfSmrg total_name_len = 0; 38835c4bbdfSmrg 38935c4bbdfSmrg pScrPriv = rrGetScrPriv(pScreen); 39035c4bbdfSmrg 39135c4bbdfSmrg if (query && pScrPriv) 39235c4bbdfSmrg if (!RRGetInfo(pScreen, query)) 39335c4bbdfSmrg return BadAlloc; 39435c4bbdfSmrg 39535c4bbdfSmrg update_totals(pScreen, pScrPriv); 39635c4bbdfSmrg 397ed6184dfSmrg xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) { 398ed6184dfSmrg if (!iter->is_output_secondary) 3991b5d61b8Smrg continue; 4001b5d61b8Smrg 40135c4bbdfSmrg pScrPriv = rrGetScrPriv(iter); 40235c4bbdfSmrg 40335c4bbdfSmrg if (query) 40435c4bbdfSmrg if (!RRGetInfo(iter, query)) 40535c4bbdfSmrg return BadAlloc; 40635c4bbdfSmrg update_totals(iter, pScrPriv); 40735c4bbdfSmrg } 40835c4bbdfSmrg 40935c4bbdfSmrg pScrPriv = rrGetScrPriv(pScreen); 41035c4bbdfSmrg rep = (xRRGetScreenResourcesReply) { 41135c4bbdfSmrg .type = X_Reply, 41235c4bbdfSmrg .sequenceNumber = client->sequence, 41335c4bbdfSmrg .length = 0, 41435c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds, 41535c4bbdfSmrg .configTimestamp = pScrPriv->lastConfigTime.milliseconds, 41635c4bbdfSmrg .nCrtcs = total_crtcs, 41735c4bbdfSmrg .nOutputs = total_outputs, 41835c4bbdfSmrg .nModes = total_modes, 41935c4bbdfSmrg .nbytesNames = total_name_len 42035c4bbdfSmrg }; 42135c4bbdfSmrg 42235c4bbdfSmrg rep.length = (total_crtcs + total_outputs + 42335c4bbdfSmrg total_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) + 42435c4bbdfSmrg bytes_to_int32(total_name_len)); 42535c4bbdfSmrg 42635c4bbdfSmrg extraLen = rep.length << 2; 42735c4bbdfSmrg if (extraLen) { 42835c4bbdfSmrg extra = malloc(extraLen); 42935c4bbdfSmrg if (!extra) { 43035c4bbdfSmrg return BadAlloc; 43135c4bbdfSmrg } 43235c4bbdfSmrg } 43335c4bbdfSmrg else 43435c4bbdfSmrg extra = NULL; 43535c4bbdfSmrg 43635c4bbdfSmrg crtcs = (RRCrtc *)extra; 43735c4bbdfSmrg outputs = (RROutput *)(crtcs + total_crtcs); 43835c4bbdfSmrg modeinfos = (xRRModeInfo *)(outputs + total_outputs); 43935c4bbdfSmrg names = (CARD8 *)(modeinfos + total_modes); 44035c4bbdfSmrg 44135c4bbdfSmrg crtc_count = 0; 44235c4bbdfSmrg output_count = 0; 44335c4bbdfSmrg mode_count = 0; 44435c4bbdfSmrg 44535c4bbdfSmrg pScrPriv = rrGetScrPriv(pScreen); 44635c4bbdfSmrg if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) { 44735c4bbdfSmrg has_primary = 1; 44835c4bbdfSmrg primary_crtc = pScrPriv->primaryOutput->crtc; 44935c4bbdfSmrg crtcs[0] = pScrPriv->primaryOutput->crtc->id; 45035c4bbdfSmrg if (client->swapped) 45135c4bbdfSmrg swapl(&crtcs[0]); 45235c4bbdfSmrg crtc_count = 1; 45335c4bbdfSmrg } 45435c4bbdfSmrg update_arrays(pScreen, pScrPriv, primary_crtc, has_primary); 45535c4bbdfSmrg 456ed6184dfSmrg xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) { 457ed6184dfSmrg if (!iter->is_output_secondary) 4581b5d61b8Smrg continue; 4591b5d61b8Smrg 46035c4bbdfSmrg pScrPriv = rrGetScrPriv(iter); 46135c4bbdfSmrg 46235c4bbdfSmrg update_arrays(iter, pScrPriv, primary_crtc, has_primary); 46335c4bbdfSmrg } 46435c4bbdfSmrg 46535c4bbdfSmrg assert(bytes_to_int32((char *) names - (char *) extra) == rep.length); 46635c4bbdfSmrg if (client->swapped) { 46735c4bbdfSmrg swaps(&rep.sequenceNumber); 46835c4bbdfSmrg swapl(&rep.length); 46935c4bbdfSmrg swapl(&rep.timestamp); 47035c4bbdfSmrg swapl(&rep.configTimestamp); 47135c4bbdfSmrg swaps(&rep.nCrtcs); 47235c4bbdfSmrg swaps(&rep.nOutputs); 47335c4bbdfSmrg swaps(&rep.nModes); 47435c4bbdfSmrg swaps(&rep.nbytesNames); 47535c4bbdfSmrg } 47635c4bbdfSmrg WriteToClient(client, sizeof(xRRGetScreenResourcesReply), &rep); 47735c4bbdfSmrg if (extraLen) { 47835c4bbdfSmrg WriteToClient(client, extraLen, extra); 47935c4bbdfSmrg free(extra); 48005b261ecSmrg } 48105b261ecSmrg return Success; 48205b261ecSmrg} 48305b261ecSmrg 4844642e01fSmrgstatic int 4854642e01fSmrgrrGetScreenResources(ClientPtr client, Bool query) 48605b261ecSmrg{ 48705b261ecSmrg REQUEST(xRRGetScreenResourcesReq); 48835c4bbdfSmrg xRRGetScreenResourcesReply rep; 48935c4bbdfSmrg WindowPtr pWin; 49035c4bbdfSmrg ScreenPtr pScreen; 49135c4bbdfSmrg rrScrPrivPtr pScrPriv; 49235c4bbdfSmrg CARD8 *extra; 49335c4bbdfSmrg unsigned long extraLen; 49435c4bbdfSmrg int i, rc, has_primary = 0; 49535c4bbdfSmrg RRCrtc *crtcs; 49635c4bbdfSmrg RROutput *outputs; 49735c4bbdfSmrg xRRModeInfo *modeinfos; 49835c4bbdfSmrg CARD8 *names; 49935c4bbdfSmrg 50005b261ecSmrg REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq); 5016747b715Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 50205b261ecSmrg if (rc != Success) 50335c4bbdfSmrg return rc; 50435c4bbdfSmrg 50505b261ecSmrg pScreen = pWin->drawable.pScreen; 50605b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 50735c4bbdfSmrg 5084642e01fSmrg if (query && pScrPriv) 50935c4bbdfSmrg if (!RRGetInfo(pScreen, query)) 51035c4bbdfSmrg return BadAlloc; 51105b261ecSmrg 512ed6184dfSmrg if (pScreen->output_secondarys) 51335c4bbdfSmrg return rrGetMultiScreenResources(client, query, pScreen); 51435c4bbdfSmrg 51535c4bbdfSmrg if (!pScrPriv) { 51635c4bbdfSmrg rep = (xRRGetScreenResourcesReply) { 51735c4bbdfSmrg .type = X_Reply, 51835c4bbdfSmrg .sequenceNumber = client->sequence, 51935c4bbdfSmrg .length = 0, 52035c4bbdfSmrg .timestamp = currentTime.milliseconds, 52135c4bbdfSmrg .configTimestamp = currentTime.milliseconds, 52235c4bbdfSmrg .nCrtcs = 0, 52335c4bbdfSmrg .nOutputs = 0, 52435c4bbdfSmrg .nModes = 0, 52535c4bbdfSmrg .nbytesNames = 0 52635c4bbdfSmrg }; 52735c4bbdfSmrg extra = NULL; 52835c4bbdfSmrg extraLen = 0; 52905b261ecSmrg } 53035c4bbdfSmrg else { 53135c4bbdfSmrg RRModePtr *modes; 53235c4bbdfSmrg int num_modes; 53335c4bbdfSmrg 53435c4bbdfSmrg modes = RRModesForScreen(pScreen, &num_modes); 53535c4bbdfSmrg if (!modes) 53635c4bbdfSmrg return BadAlloc; 53735c4bbdfSmrg 53835c4bbdfSmrg rep = (xRRGetScreenResourcesReply) { 53935c4bbdfSmrg .type = X_Reply, 54035c4bbdfSmrg .sequenceNumber = client->sequence, 54135c4bbdfSmrg .length = 0, 54235c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds, 54335c4bbdfSmrg .configTimestamp = pScrPriv->lastConfigTime.milliseconds, 54435c4bbdfSmrg .nCrtcs = pScrPriv->numCrtcs, 54535c4bbdfSmrg .nOutputs = pScrPriv->numOutputs, 54635c4bbdfSmrg .nModes = num_modes, 54735c4bbdfSmrg .nbytesNames = 0 54835c4bbdfSmrg }; 54935c4bbdfSmrg 55035c4bbdfSmrg 55135c4bbdfSmrg for (i = 0; i < num_modes; i++) 55235c4bbdfSmrg rep.nbytesNames += modes[i]->mode.nameLength; 55335c4bbdfSmrg 55435c4bbdfSmrg rep.length = (pScrPriv->numCrtcs + 55535c4bbdfSmrg pScrPriv->numOutputs + 55635c4bbdfSmrg num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) + 55735c4bbdfSmrg bytes_to_int32(rep.nbytesNames)); 55835c4bbdfSmrg 55935c4bbdfSmrg extraLen = rep.length << 2; 56035c4bbdfSmrg if (extraLen) { 5611b5d61b8Smrg extra = calloc(1, extraLen); 56235c4bbdfSmrg if (!extra) { 56335c4bbdfSmrg free(modes); 56435c4bbdfSmrg return BadAlloc; 56535c4bbdfSmrg } 56635c4bbdfSmrg } 56735c4bbdfSmrg else 56835c4bbdfSmrg extra = NULL; 56935c4bbdfSmrg 57035c4bbdfSmrg crtcs = (RRCrtc *) extra; 57135c4bbdfSmrg outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs); 57235c4bbdfSmrg modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs); 57335c4bbdfSmrg names = (CARD8 *) (modeinfos + num_modes); 57435c4bbdfSmrg 57535c4bbdfSmrg if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) { 57635c4bbdfSmrg has_primary = 1; 57735c4bbdfSmrg crtcs[0] = pScrPriv->primaryOutput->crtc->id; 57835c4bbdfSmrg if (client->swapped) 57935c4bbdfSmrg swapl(&crtcs[0]); 58035c4bbdfSmrg } 58135c4bbdfSmrg 58235c4bbdfSmrg for (i = 0; i < pScrPriv->numCrtcs; i++) { 58335c4bbdfSmrg if (has_primary && 58435c4bbdfSmrg pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) { 58535c4bbdfSmrg has_primary = 0; 58635c4bbdfSmrg continue; 58735c4bbdfSmrg } 58835c4bbdfSmrg crtcs[i + has_primary] = pScrPriv->crtcs[i]->id; 58935c4bbdfSmrg if (client->swapped) 59035c4bbdfSmrg swapl(&crtcs[i + has_primary]); 59135c4bbdfSmrg } 59235c4bbdfSmrg 59335c4bbdfSmrg for (i = 0; i < pScrPriv->numOutputs; i++) { 59435c4bbdfSmrg outputs[i] = pScrPriv->outputs[i]->id; 59535c4bbdfSmrg if (client->swapped) 59635c4bbdfSmrg swapl(&outputs[i]); 59735c4bbdfSmrg } 59835c4bbdfSmrg 59935c4bbdfSmrg for (i = 0; i < num_modes; i++) { 60035c4bbdfSmrg RRModePtr mode = modes[i]; 60135c4bbdfSmrg 60235c4bbdfSmrg modeinfos[i] = mode->mode; 60335c4bbdfSmrg if (client->swapped) { 60435c4bbdfSmrg swapl(&modeinfos[i].id); 60535c4bbdfSmrg swaps(&modeinfos[i].width); 60635c4bbdfSmrg swaps(&modeinfos[i].height); 60735c4bbdfSmrg swapl(&modeinfos[i].dotClock); 60835c4bbdfSmrg swaps(&modeinfos[i].hSyncStart); 60935c4bbdfSmrg swaps(&modeinfos[i].hSyncEnd); 61035c4bbdfSmrg swaps(&modeinfos[i].hTotal); 61135c4bbdfSmrg swaps(&modeinfos[i].hSkew); 61235c4bbdfSmrg swaps(&modeinfos[i].vSyncStart); 61335c4bbdfSmrg swaps(&modeinfos[i].vSyncEnd); 61435c4bbdfSmrg swaps(&modeinfos[i].vTotal); 61535c4bbdfSmrg swaps(&modeinfos[i].nameLength); 61635c4bbdfSmrg swapl(&modeinfos[i].modeFlags); 61735c4bbdfSmrg } 61835c4bbdfSmrg memcpy(names, mode->name, mode->mode.nameLength); 61935c4bbdfSmrg names += mode->mode.nameLength; 62035c4bbdfSmrg } 6216747b715Smrg free(modes); 62235c4bbdfSmrg assert(bytes_to_int32((char *) names - (char *) extra) == rep.length); 62305b261ecSmrg } 62435c4bbdfSmrg 62505b261ecSmrg if (client->swapped) { 62635c4bbdfSmrg swaps(&rep.sequenceNumber); 62735c4bbdfSmrg swapl(&rep.length); 62835c4bbdfSmrg swapl(&rep.timestamp); 62935c4bbdfSmrg swapl(&rep.configTimestamp); 63035c4bbdfSmrg swaps(&rep.nCrtcs); 63135c4bbdfSmrg swaps(&rep.nOutputs); 63235c4bbdfSmrg swaps(&rep.nModes); 63335c4bbdfSmrg swaps(&rep.nbytesNames); 63435c4bbdfSmrg } 63535c4bbdfSmrg WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *) &rep); 63635c4bbdfSmrg if (extraLen) { 63735c4bbdfSmrg WriteToClient(client, extraLen, (char *) extra); 63835c4bbdfSmrg free(extra); 63905b261ecSmrg } 6406747b715Smrg return Success; 64105b261ecSmrg} 64205b261ecSmrg 6434642e01fSmrgint 64435c4bbdfSmrgProcRRGetScreenResources(ClientPtr client) 6454642e01fSmrg{ 6464642e01fSmrg return rrGetScreenResources(client, TRUE); 6474642e01fSmrg} 64835c4bbdfSmrg 6494642e01fSmrgint 65035c4bbdfSmrgProcRRGetScreenResourcesCurrent(ClientPtr client) 6514642e01fSmrg{ 6524642e01fSmrg return rrGetScreenResources(client, FALSE); 6534642e01fSmrg} 6544642e01fSmrg 65505b261ecSmrgtypedef struct _RR10Data { 65605b261ecSmrg RRScreenSizePtr sizes; 65735c4bbdfSmrg int nsize; 65835c4bbdfSmrg int nrefresh; 65935c4bbdfSmrg int size; 66035c4bbdfSmrg CARD16 refresh; 66105b261ecSmrg} RR10DataRec, *RR10DataPtr; 66205b261ecSmrg 66305b261ecSmrg/* 66405b261ecSmrg * Convert 1.2 monitor data into 1.0 screen data 66505b261ecSmrg */ 66605b261ecSmrgstatic RR10DataPtr 66735c4bbdfSmrgRR10GetData(ScreenPtr pScreen, RROutputPtr output) 66805b261ecSmrg{ 66935c4bbdfSmrg RR10DataPtr data; 67005b261ecSmrg RRScreenSizePtr size; 67135c4bbdfSmrg int nmode = output->numModes + output->numUserModes; 67235c4bbdfSmrg int o, os, l, r; 67305b261ecSmrg RRScreenRatePtr refresh; 67435c4bbdfSmrg CARD16 vRefresh; 67535c4bbdfSmrg RRModePtr mode; 67635c4bbdfSmrg Bool *used; 67705b261ecSmrg 67805b261ecSmrg /* Make sure there is plenty of space for any combination */ 67935c4bbdfSmrg data = malloc(sizeof(RR10DataRec) + 68035c4bbdfSmrg sizeof(RRScreenSize) * nmode + 68135c4bbdfSmrg sizeof(RRScreenRate) * nmode + sizeof(Bool) * nmode); 68205b261ecSmrg if (!data) 68335c4bbdfSmrg return NULL; 68405b261ecSmrg size = (RRScreenSizePtr) (data + 1); 68505b261ecSmrg refresh = (RRScreenRatePtr) (size + nmode); 68605b261ecSmrg used = (Bool *) (refresh + nmode); 68735c4bbdfSmrg memset(used, '\0', sizeof(Bool) * nmode); 68805b261ecSmrg data->sizes = size; 68905b261ecSmrg data->nsize = 0; 69005b261ecSmrg data->nrefresh = 0; 69105b261ecSmrg data->size = 0; 69205b261ecSmrg data->refresh = 0; 69335c4bbdfSmrg 69405b261ecSmrg /* 69505b261ecSmrg * find modes not yet listed 69605b261ecSmrg */ 69735c4bbdfSmrg for (o = 0; o < output->numModes + output->numUserModes; o++) { 69835c4bbdfSmrg if (used[o]) 69935c4bbdfSmrg continue; 70035c4bbdfSmrg 70135c4bbdfSmrg if (o < output->numModes) 70235c4bbdfSmrg mode = output->modes[o]; 70335c4bbdfSmrg else 70435c4bbdfSmrg mode = output->userModes[o - output->numModes]; 70535c4bbdfSmrg 70635c4bbdfSmrg l = data->nsize; 70735c4bbdfSmrg size[l].id = data->nsize; 70835c4bbdfSmrg size[l].width = mode->mode.width; 70935c4bbdfSmrg size[l].height = mode->mode.height; 71035c4bbdfSmrg if (output->mmWidth && output->mmHeight) { 71135c4bbdfSmrg size[l].mmWidth = output->mmWidth; 71235c4bbdfSmrg size[l].mmHeight = output->mmHeight; 71335c4bbdfSmrg } 71435c4bbdfSmrg else { 71535c4bbdfSmrg size[l].mmWidth = pScreen->mmWidth; 71635c4bbdfSmrg size[l].mmHeight = pScreen->mmHeight; 71735c4bbdfSmrg } 71835c4bbdfSmrg size[l].nRates = 0; 71935c4bbdfSmrg size[l].pRates = &refresh[data->nrefresh]; 72035c4bbdfSmrg data->nsize++; 72135c4bbdfSmrg 72235c4bbdfSmrg /* 72335c4bbdfSmrg * Find all modes with matching size 72435c4bbdfSmrg */ 72535c4bbdfSmrg for (os = o; os < output->numModes + output->numUserModes; os++) { 72635c4bbdfSmrg if (os < output->numModes) 72735c4bbdfSmrg mode = output->modes[os]; 72835c4bbdfSmrg else 72935c4bbdfSmrg mode = output->userModes[os - output->numModes]; 73035c4bbdfSmrg if (mode->mode.width == size[l].width && 73135c4bbdfSmrg mode->mode.height == size[l].height) { 73235c4bbdfSmrg vRefresh = RRVerticalRefresh(&mode->mode); 73335c4bbdfSmrg used[os] = TRUE; 73435c4bbdfSmrg 73535c4bbdfSmrg for (r = 0; r < size[l].nRates; r++) 73635c4bbdfSmrg if (vRefresh == size[l].pRates[r].rate) 73735c4bbdfSmrg break; 73835c4bbdfSmrg if (r == size[l].nRates) { 73935c4bbdfSmrg size[l].pRates[r].rate = vRefresh; 74035c4bbdfSmrg size[l].pRates[r].mode = mode; 74135c4bbdfSmrg size[l].nRates++; 74235c4bbdfSmrg data->nrefresh++; 74335c4bbdfSmrg } 74435c4bbdfSmrg if (mode == output->crtc->mode) { 74535c4bbdfSmrg data->size = l; 74635c4bbdfSmrg data->refresh = vRefresh; 74735c4bbdfSmrg } 74835c4bbdfSmrg } 74935c4bbdfSmrg } 75005b261ecSmrg } 75105b261ecSmrg return data; 75205b261ecSmrg} 75305b261ecSmrg 75405b261ecSmrgint 75535c4bbdfSmrgProcRRGetScreenInfo(ClientPtr client) 75605b261ecSmrg{ 75705b261ecSmrg REQUEST(xRRGetScreenInfoReq); 75835c4bbdfSmrg xRRGetScreenInfoReply rep; 75935c4bbdfSmrg WindowPtr pWin; 76035c4bbdfSmrg int rc; 76135c4bbdfSmrg ScreenPtr pScreen; 76235c4bbdfSmrg rrScrPrivPtr pScrPriv; 76335c4bbdfSmrg CARD8 *extra; 76435c4bbdfSmrg unsigned long extraLen; 76535c4bbdfSmrg RROutputPtr output; 76605b261ecSmrg 76705b261ecSmrg REQUEST_SIZE_MATCH(xRRGetScreenInfoReq); 7686747b715Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 76905b261ecSmrg if (rc != Success) 77035c4bbdfSmrg return rc; 77105b261ecSmrg 77205b261ecSmrg pScreen = pWin->drawable.pScreen; 77305b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 77435c4bbdfSmrg 77505b261ecSmrg if (pScrPriv) 77635c4bbdfSmrg if (!RRGetInfo(pScreen, TRUE)) 77735c4bbdfSmrg return BadAlloc; 77835c4bbdfSmrg 77935c4bbdfSmrg output = RRFirstOutput(pScreen); 78035c4bbdfSmrg 78135c4bbdfSmrg if (!pScrPriv || !output) { 78235c4bbdfSmrg rep = (xRRGetScreenInfoReply) { 78335c4bbdfSmrg .type = X_Reply, 78435c4bbdfSmrg .setOfRotations = RR_Rotate_0, 78535c4bbdfSmrg .sequenceNumber = client->sequence, 78635c4bbdfSmrg .length = 0, 78735c4bbdfSmrg .root = pWin->drawable.pScreen->root->drawable.id, 78835c4bbdfSmrg .timestamp = currentTime.milliseconds, 78935c4bbdfSmrg .configTimestamp = currentTime.milliseconds, 79035c4bbdfSmrg .nSizes = 0, 79135c4bbdfSmrg .sizeID = 0, 79235c4bbdfSmrg .rotation = RR_Rotate_0, 79335c4bbdfSmrg .rate = 0, 79435c4bbdfSmrg .nrateEnts = 0 79535c4bbdfSmrg }; 79635c4bbdfSmrg extra = 0; 79735c4bbdfSmrg extraLen = 0; 79805b261ecSmrg } 79935c4bbdfSmrg else { 80035c4bbdfSmrg int i, j; 80135c4bbdfSmrg xScreenSizes *size; 80235c4bbdfSmrg CARD16 *rates; 80335c4bbdfSmrg CARD8 *data8; 80435c4bbdfSmrg Bool has_rate = RRClientKnowsRates(client); 80535c4bbdfSmrg RR10DataPtr pData; 80635c4bbdfSmrg RRScreenSizePtr pSize; 80735c4bbdfSmrg 80835c4bbdfSmrg pData = RR10GetData(pScreen, output); 80935c4bbdfSmrg if (!pData) 81035c4bbdfSmrg return BadAlloc; 81135c4bbdfSmrg 81235c4bbdfSmrg rep = (xRRGetScreenInfoReply) { 81335c4bbdfSmrg .type = X_Reply, 81435c4bbdfSmrg .setOfRotations = output->crtc->rotations, 81535c4bbdfSmrg .sequenceNumber = client->sequence, 81635c4bbdfSmrg .length = 0, 81735c4bbdfSmrg .root = pWin->drawable.pScreen->root->drawable.id, 81835c4bbdfSmrg .timestamp = pScrPriv->lastSetTime.milliseconds, 81935c4bbdfSmrg .configTimestamp = pScrPriv->lastConfigTime.milliseconds, 82035c4bbdfSmrg .rotation = output->crtc->rotation, 82135c4bbdfSmrg .nSizes = pData->nsize, 82235c4bbdfSmrg .nrateEnts = pData->nrefresh + pData->nsize, 82335c4bbdfSmrg .sizeID = pData->size, 82435c4bbdfSmrg .rate = pData->refresh 82535c4bbdfSmrg }; 82635c4bbdfSmrg 82735c4bbdfSmrg extraLen = rep.nSizes * sizeof(xScreenSizes); 82835c4bbdfSmrg if (has_rate) 82935c4bbdfSmrg extraLen += rep.nrateEnts * sizeof(CARD16); 83035c4bbdfSmrg 83135c4bbdfSmrg if (extraLen) { 83235c4bbdfSmrg extra = (CARD8 *) malloc(extraLen); 83335c4bbdfSmrg if (!extra) { 83435c4bbdfSmrg free(pData); 83535c4bbdfSmrg return BadAlloc; 83635c4bbdfSmrg } 83735c4bbdfSmrg } 83835c4bbdfSmrg else 83935c4bbdfSmrg extra = NULL; 84035c4bbdfSmrg 84135c4bbdfSmrg /* 84235c4bbdfSmrg * First comes the size information 84335c4bbdfSmrg */ 84435c4bbdfSmrg size = (xScreenSizes *) extra; 84535c4bbdfSmrg rates = (CARD16 *) (size + rep.nSizes); 84635c4bbdfSmrg for (i = 0; i < pData->nsize; i++) { 84735c4bbdfSmrg pSize = &pData->sizes[i]; 84835c4bbdfSmrg size->widthInPixels = pSize->width; 84935c4bbdfSmrg size->heightInPixels = pSize->height; 85035c4bbdfSmrg size->widthInMillimeters = pSize->mmWidth; 85135c4bbdfSmrg size->heightInMillimeters = pSize->mmHeight; 85235c4bbdfSmrg if (client->swapped) { 85335c4bbdfSmrg swaps(&size->widthInPixels); 85435c4bbdfSmrg swaps(&size->heightInPixels); 85535c4bbdfSmrg swaps(&size->widthInMillimeters); 85635c4bbdfSmrg swaps(&size->heightInMillimeters); 85735c4bbdfSmrg } 85835c4bbdfSmrg size++; 85935c4bbdfSmrg if (has_rate) { 86035c4bbdfSmrg *rates = pSize->nRates; 86135c4bbdfSmrg if (client->swapped) { 86235c4bbdfSmrg swaps(rates); 86335c4bbdfSmrg } 86435c4bbdfSmrg rates++; 86535c4bbdfSmrg for (j = 0; j < pSize->nRates; j++) { 86635c4bbdfSmrg *rates = pSize->pRates[j].rate; 86735c4bbdfSmrg if (client->swapped) { 86835c4bbdfSmrg swaps(rates); 86935c4bbdfSmrg } 87035c4bbdfSmrg rates++; 87135c4bbdfSmrg } 87235c4bbdfSmrg } 87335c4bbdfSmrg } 8746747b715Smrg free(pData); 87505b261ecSmrg 87635c4bbdfSmrg data8 = (CARD8 *) rates; 87735c4bbdfSmrg 87835c4bbdfSmrg if (data8 - (CARD8 *) extra != extraLen) 87935c4bbdfSmrg FatalError("RRGetScreenInfo bad extra len %ld != %ld\n", 88035c4bbdfSmrg (unsigned long) (data8 - (CARD8 *) extra), extraLen); 88135c4bbdfSmrg rep.length = bytes_to_int32(extraLen); 88205b261ecSmrg } 88305b261ecSmrg if (client->swapped) { 88435c4bbdfSmrg swaps(&rep.sequenceNumber); 88535c4bbdfSmrg swapl(&rep.length); 88635c4bbdfSmrg swapl(&rep.timestamp); 88735c4bbdfSmrg swapl(&rep.configTimestamp); 88835c4bbdfSmrg swaps(&rep.rotation); 88935c4bbdfSmrg swaps(&rep.nSizes); 89035c4bbdfSmrg swaps(&rep.sizeID); 89135c4bbdfSmrg swaps(&rep.rate); 89235c4bbdfSmrg swaps(&rep.nrateEnts); 89335c4bbdfSmrg } 89435c4bbdfSmrg WriteToClient(client, sizeof(xRRGetScreenInfoReply), &rep); 89535c4bbdfSmrg if (extraLen) { 89635c4bbdfSmrg WriteToClient(client, extraLen, extra); 89735c4bbdfSmrg free(extra); 89805b261ecSmrg } 8996747b715Smrg return Success; 90005b261ecSmrg} 90105b261ecSmrg 90205b261ecSmrgint 90335c4bbdfSmrgProcRRSetScreenConfig(ClientPtr client) 90405b261ecSmrg{ 90505b261ecSmrg REQUEST(xRRSetScreenConfigReq); 90605b261ecSmrg xRRSetScreenConfigReply rep; 90735c4bbdfSmrg DrawablePtr pDraw; 90835c4bbdfSmrg int rc; 90935c4bbdfSmrg ScreenPtr pScreen; 91035c4bbdfSmrg rrScrPrivPtr pScrPriv; 91135c4bbdfSmrg TimeStamp time; 91235c4bbdfSmrg int i; 91335c4bbdfSmrg Rotation rotation; 91435c4bbdfSmrg int rate; 91535c4bbdfSmrg Bool has_rate; 91635c4bbdfSmrg CARD8 status; 91735c4bbdfSmrg RROutputPtr output; 91835c4bbdfSmrg RRCrtcPtr crtc; 91935c4bbdfSmrg RRModePtr mode; 92035c4bbdfSmrg RR10DataPtr pData = NULL; 92135c4bbdfSmrg RRScreenSizePtr pSize; 92235c4bbdfSmrg int width, height; 92335c4bbdfSmrg 92435c4bbdfSmrg UpdateCurrentTime(); 92535c4bbdfSmrg 92635c4bbdfSmrg if (RRClientKnowsRates(client)) { 92735c4bbdfSmrg REQUEST_SIZE_MATCH(xRRSetScreenConfigReq); 92835c4bbdfSmrg has_rate = TRUE; 92905b261ecSmrg } 93035c4bbdfSmrg else { 93135c4bbdfSmrg REQUEST_SIZE_MATCH(xRR1_0SetScreenConfigReq); 93235c4bbdfSmrg has_rate = FALSE; 93305b261ecSmrg } 93435c4bbdfSmrg 93505b261ecSmrg rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess); 93605b261ecSmrg if (rc != Success) 93735c4bbdfSmrg return rc; 93805b261ecSmrg 93905b261ecSmrg pScreen = pDraw->pScreen; 94005b261ecSmrg 94105b261ecSmrg pScrPriv = rrGetScrPriv(pScreen); 94235c4bbdfSmrg 94305b261ecSmrg time = ClientTimeToServerTime(stuff->timestamp); 94435c4bbdfSmrg 94535c4bbdfSmrg if (!pScrPriv) { 94635c4bbdfSmrg time = currentTime; 94735c4bbdfSmrg status = RRSetConfigFailed; 94835c4bbdfSmrg goto sendReply; 94935c4bbdfSmrg } 95035c4bbdfSmrg if (!RRGetInfo(pScreen, FALSE)) 95135c4bbdfSmrg return BadAlloc; 95235c4bbdfSmrg 95335c4bbdfSmrg output = RRFirstOutput(pScreen); 95435c4bbdfSmrg if (!output) { 95535c4bbdfSmrg time = currentTime; 95635c4bbdfSmrg status = RRSetConfigFailed; 95735c4bbdfSmrg goto sendReply; 95805b261ecSmrg } 95905b261ecSmrg 96005b261ecSmrg crtc = output->crtc; 96105b261ecSmrg 96205b261ecSmrg /* 96305b261ecSmrg * If the client's config timestamp is not the same as the last config 96405b261ecSmrg * timestamp, then the config information isn't up-to-date and 96505b261ecSmrg * can't even be validated. 96605b261ecSmrg * 96705b261ecSmrg * Note that the client only knows about the milliseconds part of the 96805b261ecSmrg * timestamp, so using CompareTimeStamps here would cause randr to suddenly 96905b261ecSmrg * stop working after several hours have passed (freedesktop bug #6502). 97005b261ecSmrg */ 97135c4bbdfSmrg if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds) { 97235c4bbdfSmrg status = RRSetConfigInvalidConfigTime; 97335c4bbdfSmrg goto sendReply; 97405b261ecSmrg } 97535c4bbdfSmrg 97635c4bbdfSmrg pData = RR10GetData(pScreen, output); 97705b261ecSmrg if (!pData) 97835c4bbdfSmrg return BadAlloc; 97935c4bbdfSmrg 98035c4bbdfSmrg if (stuff->sizeID >= pData->nsize) { 98135c4bbdfSmrg /* 98235c4bbdfSmrg * Invalid size ID 98335c4bbdfSmrg */ 98435c4bbdfSmrg client->errorValue = stuff->sizeID; 98535c4bbdfSmrg free(pData); 98635c4bbdfSmrg return BadValue; 98705b261ecSmrg } 98805b261ecSmrg pSize = &pData->sizes[stuff->sizeID]; 98935c4bbdfSmrg 99005b261ecSmrg /* 99105b261ecSmrg * Validate requested rotation 99205b261ecSmrg */ 99305b261ecSmrg rotation = (Rotation) stuff->rotation; 99405b261ecSmrg 99505b261ecSmrg /* test the rotation bits only! */ 99605b261ecSmrg switch (rotation & 0xf) { 99705b261ecSmrg case RR_Rotate_0: 99805b261ecSmrg case RR_Rotate_90: 99905b261ecSmrg case RR_Rotate_180: 100005b261ecSmrg case RR_Rotate_270: 100135c4bbdfSmrg break; 100205b261ecSmrg default: 100335c4bbdfSmrg /* 100435c4bbdfSmrg * Invalid rotation 100535c4bbdfSmrg */ 100635c4bbdfSmrg client->errorValue = stuff->rotation; 100735c4bbdfSmrg free(pData); 100835c4bbdfSmrg return BadValue; 100905b261ecSmrg } 101005b261ecSmrg 101135c4bbdfSmrg if ((~crtc->rotations) & rotation) { 101235c4bbdfSmrg /* 101335c4bbdfSmrg * requested rotation or reflection not supported by screen 101435c4bbdfSmrg */ 101535c4bbdfSmrg client->errorValue = stuff->rotation; 101635c4bbdfSmrg free(pData); 101735c4bbdfSmrg return BadMatch; 101805b261ecSmrg } 101905b261ecSmrg 102005b261ecSmrg /* 102105b261ecSmrg * Validate requested refresh 102205b261ecSmrg */ 102305b261ecSmrg if (has_rate) 102435c4bbdfSmrg rate = (int) stuff->rate; 102505b261ecSmrg else 102635c4bbdfSmrg rate = 0; 102735c4bbdfSmrg 102835c4bbdfSmrg if (rate) { 102935c4bbdfSmrg for (i = 0; i < pSize->nRates; i++) { 103035c4bbdfSmrg if (pSize->pRates[i].rate == rate) 103135c4bbdfSmrg break; 103235c4bbdfSmrg } 103335c4bbdfSmrg if (i == pSize->nRates) { 103435c4bbdfSmrg /* 103535c4bbdfSmrg * Invalid rate 103635c4bbdfSmrg */ 103735c4bbdfSmrg client->errorValue = rate; 103835c4bbdfSmrg free(pData); 103935c4bbdfSmrg return BadValue; 104035c4bbdfSmrg } 104135c4bbdfSmrg mode = pSize->pRates[i].mode; 104205b261ecSmrg } 104305b261ecSmrg else 104435c4bbdfSmrg mode = pSize->pRates[0].mode; 104535c4bbdfSmrg 104605b261ecSmrg /* 104705b261ecSmrg * Make sure the requested set-time is not older than 104805b261ecSmrg * the last set-time 104905b261ecSmrg */ 105035c4bbdfSmrg if (CompareTimeStamps(time, pScrPriv->lastSetTime) < 0) { 105135c4bbdfSmrg status = RRSetConfigInvalidTime; 105235c4bbdfSmrg goto sendReply; 105305b261ecSmrg } 105405b261ecSmrg 105505b261ecSmrg /* 105605b261ecSmrg * If the screen size is changing, adjust all of the other outputs 105705b261ecSmrg * to fit the new size, mirroring as much as possible 105805b261ecSmrg */ 105905b261ecSmrg width = mode->mode.width; 106005b261ecSmrg height = mode->mode.height; 10618223e2f2Smrg if (width < pScrPriv->minWidth || pScrPriv->maxWidth < width) { 106235c4bbdfSmrg client->errorValue = width; 106335c4bbdfSmrg free(pData); 106435c4bbdfSmrg return BadValue; 10658223e2f2Smrg } 10668223e2f2Smrg if (height < pScrPriv->minHeight || pScrPriv->maxHeight < height) { 106735c4bbdfSmrg client->errorValue = height; 106835c4bbdfSmrg free(pData); 106935c4bbdfSmrg return BadValue; 107035c4bbdfSmrg } 107135c4bbdfSmrg 107235c4bbdfSmrg if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 107335c4bbdfSmrg width = mode->mode.height; 107435c4bbdfSmrg height = mode->mode.width; 107535c4bbdfSmrg } 107635c4bbdfSmrg 107735c4bbdfSmrg if (width != pScreen->width || height != pScreen->height) { 107835c4bbdfSmrg int c; 107935c4bbdfSmrg 108035c4bbdfSmrg for (c = 0; c < pScrPriv->numCrtcs; c++) { 108135c4bbdfSmrg if (!RRCrtcSet(pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0, 108235c4bbdfSmrg 0, NULL)) { 108335c4bbdfSmrg status = RRSetConfigFailed; 108435c4bbdfSmrg /* XXX recover from failure */ 108535c4bbdfSmrg goto sendReply; 108635c4bbdfSmrg } 108735c4bbdfSmrg } 108835c4bbdfSmrg if (!RRScreenSizeSet(pScreen, width, height, 108935c4bbdfSmrg pScreen->mmWidth, pScreen->mmHeight)) { 109035c4bbdfSmrg status = RRSetConfigFailed; 109135c4bbdfSmrg /* XXX recover from failure */ 109235c4bbdfSmrg goto sendReply; 109335c4bbdfSmrg } 109435c4bbdfSmrg } 109535c4bbdfSmrg 109635c4bbdfSmrg if (!RRCrtcSet(crtc, mode, 0, 0, stuff->rotation, 1, &output)) 109735c4bbdfSmrg status = RRSetConfigFailed; 109852397711Smrg else { 109935c4bbdfSmrg pScrPriv->lastSetTime = time; 110035c4bbdfSmrg status = RRSetConfigSuccess; 110152397711Smrg } 110205b261ecSmrg 110305b261ecSmrg /* 110405b261ecSmrg * XXX Configure other crtcs to mirror as much as possible 110505b261ecSmrg */ 110635c4bbdfSmrg 110735c4bbdfSmrg sendReply: 110835c4bbdfSmrg 11096747b715Smrg free(pData); 111005b261ecSmrg 111135c4bbdfSmrg rep = (xRRSetScreenConfigReply) { 111235c4bbdfSmrg .type = X_Reply, 111335c4bbdfSmrg .status = status, 111435c4bbdfSmrg .sequenceNumber = client->sequence, 111535c4bbdfSmrg .length = 0, 111605b261ecSmrg 111735c4bbdfSmrg .newTimestamp = pScrPriv->lastSetTime.milliseconds, 111835c4bbdfSmrg .newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds, 111935c4bbdfSmrg .root = pDraw->pScreen->root->drawable.id, 112035c4bbdfSmrg /* .subpixelOrder = ?? */ 112135c4bbdfSmrg }; 112205b261ecSmrg 112335c4bbdfSmrg if (client->swapped) { 112435c4bbdfSmrg swaps(&rep.sequenceNumber); 112535c4bbdfSmrg swapl(&rep.length); 112635c4bbdfSmrg swapl(&rep.newTimestamp); 112735c4bbdfSmrg swapl(&rep.newConfigTimestamp); 112835c4bbdfSmrg swapl(&rep.root); 112905b261ecSmrg } 113035c4bbdfSmrg WriteToClient(client, sizeof(xRRSetScreenConfigReply), &rep); 113105b261ecSmrg 11326747b715Smrg return Success; 113305b261ecSmrg} 113405b261ecSmrg 113505b261ecSmrgstatic CARD16 113635c4bbdfSmrgRR10CurrentSizeID(ScreenPtr pScreen) 113705b261ecSmrg{ 113835c4bbdfSmrg CARD16 sizeID = 0xffff; 113935c4bbdfSmrg RROutputPtr output = RRFirstOutput(pScreen); 114035c4bbdfSmrg 114135c4bbdfSmrg if (output) { 114235c4bbdfSmrg RR10DataPtr data = RR10GetData(pScreen, output); 114335c4bbdfSmrg 114435c4bbdfSmrg if (data) { 114535c4bbdfSmrg int i; 114635c4bbdfSmrg 114735c4bbdfSmrg for (i = 0; i < data->nsize; i++) 114835c4bbdfSmrg if (data->sizes[i].width == pScreen->width && 114935c4bbdfSmrg data->sizes[i].height == pScreen->height) { 115035c4bbdfSmrg sizeID = (CARD16) i; 115135c4bbdfSmrg break; 115235c4bbdfSmrg } 115335c4bbdfSmrg free(data); 115435c4bbdfSmrg } 115505b261ecSmrg } 115605b261ecSmrg return sizeID; 115705b261ecSmrg} 1158