387
463
resInfoX->canUseVMwareCtrlTopologySet = FALSE;
391
466
return resInfoX->canUseVMwareCtrlTopologySet;
474
* Employs the RandR 1.2 extension to set a new display topology.
476
* @return TRUE if operation succeeded, FALSE otherwise.
480
RandR12_SetTopology(unsigned int ndisplays,
481
// IN: number of elements in topology
482
xXineramaScreenInfo *displays,
483
// IN: array of display geometries
485
// IN: total width of topology
487
// IN: total height of topology
489
ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
490
int minWidth, minHeight, maxWidth, maxHeight;
491
XRRScreenResources* xrrRes = NULL;
492
XRROutputInfo** xrrOutputs;
493
unsigned int numOutputs;
494
unsigned int* outputMap;
495
XRRCrtcInfo** xrrCrtcs;
496
XRRScreenConfiguration* xrrConfig = NULL;
497
XRRScreenSize* xrrSizes;
498
Rotation xrrCurRotation;
501
XRRModeInfo xrrModes[ndisplays];
502
char name[RR12_MODE_MAXLEN];
505
Bool success = FALSE;
507
if (!XRRGetScreenSizeRange(resInfoX->display, resInfoX->rootWindow,
508
&minWidth, &minHeight, &maxWidth, &maxHeight) ||
509
width < minWidth || height < minHeight ||
510
width > maxWidth || height > maxHeight) {
514
/* Grab the server for two reasons:
515
* - Avoid race conditions with other clients changing RandR configuration.
516
* - Make our changes appear as atomic as possible to other clients.
518
XGrabServer(resInfoX->display);
520
xrrRes = XRRGetScreenResources(resInfoX->display, resInfoX->rootWindow);
525
xrrCrtcs = Util_SafeCalloc(sizeof *xrrCrtcs, xrrRes->ncrtc);
526
xrrOutputs = Util_SafeCalloc(sizeof *xrrOutputs, xrrRes->noutput);
527
outputMap = Util_SafeCalloc(sizeof *outputMap, xrrRes->noutput);
529
/* RandR may enumerate outputs differently from the host. Apply the nth
530
* topology rectangle to the output called LVDS<n>.
532
for (i = 0; i < xrrRes->noutput; i++) {
537
for (i = 0; i < xrrRes->noutput; i++) {
540
xrrOutputs[i] = XRRGetOutputInfo(resInfoX->display, xrrRes,
543
if (!xrrOutputs[i]) {
547
if (sscanf(xrrOutputs[i]->name, RR12_OUTPUT_FORMAT, &num) != 1 ||
552
outputMap[num - 1] = i;
554
if (num > numOutputs) {
559
/* Disable any CRTCs which won't be used or wont't fit in new screen size. */
560
for (i = 0; i < xrrRes->ncrtc; i++) {
561
xrrCrtcs[i] = XRRGetCrtcInfo(resInfoX->display, xrrRes,
568
for (j = 0; j < numOutputs; j++) {
569
if (xrrOutputs[outputMap[j]]->crtc == xrrRes->crtcs[i]) {
574
if (xrrCrtcs[i]->mode == None ||
576
(xrrCrtcs[i]->x + xrrCrtcs[i]->width) <= width &&
577
(xrrCrtcs[i]->y + xrrCrtcs[i]->height) <= height)) {
581
if (XRRSetCrtcConfig(resInfoX->display, xrrRes, xrrRes->crtcs[i],
582
xrrCrtcs[i]->timestamp, 0, 0, None, RR_Rotate_0, NULL, 0)
588
/* Set new screen size. */
589
xrrConfig = XRRGetScreenInfo(resInfoX->display, resInfoX->rootWindow);
590
xrrSizes = XRRConfigSizes(xrrConfig, &xrrNumSizes);
591
currentSize = XRRConfigCurrentConfiguration(xrrConfig, &xrrCurRotation);
593
if (xrrSizes[currentSize].mheight > 0) {
594
dpi = MILLIS_PER_INCH * xrrSizes[currentSize].height / xrrSizes[currentSize].mheight;
597
dpi = RR12_DEFAULT_DPI;
600
dpi = RR12_DEFAULT_DPI;
603
XRRSetScreenSize(resInfoX->display, resInfoX->rootWindow, width, height,
604
(MILLIS_PER_INCH * width) / dpi,
605
(MILLIS_PER_INCH * height) / dpi);
607
/* Set new topology. */
608
for (i = 0; i < numOutputs; i++) {
609
memset(xrrModes + i, 0, sizeof xrrModes[0]);
611
xrrModes[i].width = displays[i].width;
612
xrrModes[i].height = displays[i].height;
614
/* Look for existing matching autofit mode. */
615
for (j = 0; j < i && !xrrModes[i].id; j++) {
616
if (xrrModes[j].id &&
617
xrrModes[j].width == displays[i].width &&
618
xrrModes[j].height == displays[i].height) {
619
xrrModes[i].id = xrrModes[j].id;
624
for (j = 0; j < xrrRes->nmode && !xrrModes[i].id; j++) {
627
if (sscanf(xrrRes->modes[j].name, RR12_MODE_FORMAT, &w, &h) == 2 &&
628
w == displays[i].width && h == displays[i].height) {
629
xrrModes[i].id = xrrRes->modes[j].id;
634
/* If no luck, create new autofit mode. */
635
if (!xrrModes[i].id) {
636
Str_Sprintf(name, sizeof name, RR12_MODE_FORMAT, displays[i].width,
638
xrrModes[i].name = name;
639
xrrModes[i].nameLength = strlen(xrrModes[i].name);
640
xrrModes[i].id = XRRCreateMode(resInfoX->display, resInfoX->rootWindow,
644
if (xrrModes[i].id == None) {
648
/* Set autofit mode. */
649
if (xrrOutputs[outputMap[i]]->crtc == None) {
650
xrrOutputs[outputMap[i]]->crtc = xrrOutputs[outputMap[i]]->crtcs[0];
653
for (j = 0; j < xrrOutputs[outputMap[i]]->nmode; j++) {
654
if (xrrModes[i].id == xrrOutputs[outputMap[i]]->modes[j]) {
658
if (j == xrrOutputs[outputMap[i]]->nmode) {
659
XRRAddOutputMode(resInfoX->display, xrrRes->outputs[outputMap[i]],
662
if (XRRSetCrtcConfig(resInfoX->display, xrrRes,
663
xrrOutputs[outputMap[i]]->crtc, xrrCrtcs[i]->timestamp,
664
displays[i].x_org, displays[i].y_org, xrrModes[i].id,
665
RR_Rotate_0, xrrRes->outputs + outputMap[i], 1)
671
/* Delete unused autofit modes. */
672
for (i = 0; i < xrrRes->nmode; i++) {
676
if (sscanf(xrrRes->modes[i].name, RR12_MODE_FORMAT, &w, &h) != 2) {
680
for (j = 0; j < xrrRes->noutput; j++) {
681
if (j < numOutputs &&
682
w == displays[j].width && h == displays[j].height) {
687
for (k = 0; k < xrrOutputs[outputMap[j]]->nmode; k++) {
688
if (xrrOutputs[outputMap[j]]->modes[k] == xrrRes->modes[i].id) {
689
XRRDeleteOutputMode(resInfoX->display,
690
xrrRes->outputs[outputMap[j]],
691
xrrOutputs[outputMap[j]]->modes[k]);
698
XRRDestroyMode(resInfoX->display, xrrRes->modes[i].id);
702
resInfoX->topologyDisplays = ndisplays;
703
resInfoX->topologyWidth = width;
704
resInfoX->topologyHeight = height;
709
XUngrabServer(resInfoX->display);
712
XRRFreeScreenConfigInfo(xrrConfig);
715
for (i = 0; i < xrrRes->noutput; i++) {
717
XRRFreeOutputInfo(xrrOutputs[i]);
720
for (i = 0; i < xrrRes->ncrtc; i++) {
722
XRRFreeCrtcInfo(xrrCrtcs[i]);
728
XRRFreeScreenResources(xrrRes);
734
#endif // ifndef NO_MULTIMON