~n-muench/ubuntu/precise/open-vm-tools/open-vm-tools-precise.sid-merge1

« back to all changes in this revision

Viewing changes to lib/resolution/resolutionX11.c

  • Committer: Evan Broder
  • Date: 2010-03-21 23:26:53 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: broder@mit.edu-20100321232653-5a57r7v7ch4o6byv
Merging shared upstream rev into target branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
44
44
#include "libvmwarectrl.h"
45
45
#include "str.h"
46
46
#include "strutil.h"
 
47
#include "util.h"
47
48
 
48
49
#define VMWAREDRV_PATH_64   "/usr/X11R6/lib64/modules/drivers/vmware_drv.o"
49
50
#define VMWAREDRV_PATH      "/usr/X11R6/lib/modules/drivers/vmware_drv.o"
50
51
#define VERSION_STRING      "VMware Guest X Server"
51
52
 
 
53
#define RR12_OUTPUT_FORMAT "LVDS%u"
 
54
#define RR12_MODE_FORMAT "autofit-%ux%u"
 
55
#define RR12_MODE_MAXLEN (sizeof RR12_MODE_FORMAT + 2 * (10 - 2) + 1)
 
56
#define RR12_DEFAULT_DPI 96.0
 
57
#define MILLIS_PER_INCH 25.4
 
58
 
52
59
 
53
60
/*
54
61
 * Describes the state of the X11 back-end of lib/resolution.
60
67
                                // TRUE if VMwareCtrl extension available
61
68
   Bool         canUseVMwareCtrlTopologySet;
62
69
                                // TRUE if VMwareCtrl extension supports topology set
 
70
   Bool         canUseRandR12;  // TRUE if RandR extension >= 1.2 available
 
71
   unsigned int topologyDisplays;
 
72
                                // Number of displays in current topology
 
73
   unsigned int topologyWidth;  // Total width of current topology
 
74
   unsigned int topologyHeight; // Total height of current topology
63
75
} ResolutionInfoX11Type;
64
76
 
65
77
 
76
88
 
77
89
static Bool ResolutionCanSet(void);
78
90
static Bool TopologyCanSet(void);
 
91
#ifndef NO_MULTIMON
 
92
static Bool RandR12_SetTopology(unsigned int ndisplays,
 
93
                                xXineramaScreenInfo *displays,
 
94
                                unsigned int width, unsigned int height);
 
95
#endif
79
96
static Bool SelectResolution(uint32 width, uint32 height);
80
97
 
81
98
 
123
140
   resInfoX->canUseVMwareCtrl = VMwareCtrl_QueryVersion(resInfoX->display, &dummy1,
124
141
                                                        &dummy2);
125
142
   resInfoX->canUseVMwareCtrlTopologySet = FALSE;
 
143
   resInfoX->canUseRandR12 = FALSE;
126
144
 
127
145
   resInfo->canSetResolution = ResolutionCanSet();
128
146
   resInfo->canSetTopology = TopologyCanSet();
280
298
      displays[i].y_org -= minY;
281
299
   }
282
300
 
283
 
   if (!VMwareCtrl_SetTopology(resInfoX->display, DefaultScreen(resInfoX->display), displays,
284
 
                               ndisplays)) {
285
 
      Debug("Failed to set topology in the driver.\n");
286
 
      goto out;
287
 
   }
288
 
 
289
 
   if (!SelectResolution(maxX - minX, maxY - minY)) {
290
 
      Debug("Failed to set new resolution.\n");
291
 
      goto out;
292
 
   }
293
 
 
294
 
   success = TRUE;
 
301
   if (resInfoX->canUseVMwareCtrlTopologySet) {
 
302
      if (!VMwareCtrl_SetTopology(resInfoX->display, DefaultScreen(resInfoX->display),
 
303
                                  displays, ndisplays)) {
 
304
         Debug("Failed to set topology in the driver.\n");
 
305
         goto out;
 
306
      }
 
307
 
 
308
      if (!SelectResolution(maxX - minX, maxY - minY)) {
 
309
         Debug("Failed to set new resolution.\n");
 
310
         goto out;
 
311
      }
 
312
 
 
313
      success = TRUE;
 
314
   } else if (resInfoX->canUseRandR12) {
 
315
      success = RandR12_SetTopology(ndisplays, displays,
 
316
                                    maxX - minX, maxY - minY);
 
317
   }
295
318
 
296
319
out:
297
320
   free(displays);
347
370
      return TRUE;
348
371
   }
349
372
 
 
373
#ifndef NO_MULTIMON
 
374
   /* See if RandR >= 1.2 can be used: The extension version is high enough and
 
375
    * all output names match the expected format.
 
376
    */
 
377
   if (major > 1 || (major == 1 && minor >= 2)) {
 
378
      XRRScreenResources* xrrRes;
 
379
      XRROutputInfo* xrrOutput;
 
380
      unsigned int num;
 
381
      int i;
 
382
 
 
383
      XGrabServer(resInfoX->display);
 
384
 
 
385
      xrrRes = XRRGetScreenResources(resInfoX->display, resInfoX->rootWindow);
 
386
 
 
387
      if (xrrRes) {
 
388
         for (i = 0; i < xrrRes->noutput; i++) {
 
389
            xrrOutput = XRRGetOutputInfo(resInfoX->display, xrrRes,
 
390
                                         xrrRes->outputs[i]);
 
391
            if (!xrrOutput) {
 
392
               break;
 
393
            }
 
394
 
 
395
            if (sscanf(xrrOutput->name, RR12_OUTPUT_FORMAT, &num) != 1 ||
 
396
                num < 1) {
 
397
               XRRFreeOutputInfo(xrrOutput);
 
398
               break;
 
399
            }
 
400
 
 
401
            XRRFreeOutputInfo(xrrOutput);
 
402
         }
 
403
 
 
404
         if (i == xrrRes->noutput) {
 
405
            resInfoX->canUseRandR12 = TRUE;
 
406
         } else {
 
407
            Debug("RandR >= 1.2 not usable\n");
 
408
         }
 
409
 
 
410
         XRRFreeScreenResources(xrrRes);
 
411
      }
 
412
 
 
413
      XUngrabServer(resInfoX->display);
 
414
 
 
415
      if (resInfoX->canUseRandR12) {
 
416
         return TRUE;
 
417
      }
 
418
   }
 
419
#endif // ifndef NO_MULTIMON
 
420
 
350
421
   /*
351
422
    * XXX: This check does not work with XOrg 6.9/7.0 for two reasons: Both
352
423
    * versions now use .so for the driver extension and 7.0 moves the drivers
430
501
   ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
431
502
#ifdef NO_MULTIMON
432
503
   resInfoX->canUseVMwareCtrlTopologySet = FALSE;
 
504
   return FALSE;
433
505
#else
434
506
   int major;
435
507
   int minor;
436
508
 
 
509
   if (resInfoX->canUseRandR12) {
 
510
      return TRUE;
 
511
   }
 
512
 
437
513
   if (resInfoX->canUseVMwareCtrl && XineramaQueryVersion(resInfoX->display, &major,
438
514
                                                          &minor)) {
439
515
      /*
443
519
   } else {
444
520
      resInfoX->canUseVMwareCtrlTopologySet = FALSE;
445
521
   }
446
 
#endif
447
522
 
448
523
   return resInfoX->canUseVMwareCtrlTopologySet;
449
 
}
 
524
#endif
 
525
}
 
526
 
 
527
 
 
528
#ifndef NO_MULTIMON
 
529
 
 
530
/*
 
531
 *-----------------------------------------------------------------------------
 
532
 *
 
533
 * RandR12_SetTopology --
 
534
 *
 
535
 *      Employs the RandR 1.2 extension to set a new display topology.
 
536
 *
 
537
 * Results:
 
538
 *      TRUE if operation succeeded, FALSE otherwise.
 
539
 *
 
540
 * Side effects:
 
541
 *      None.
 
542
 *
 
543
 *-----------------------------------------------------------------------------
 
544
 */
 
545
 
 
546
static Bool
 
547
RandR12_SetTopology(unsigned int ndisplays,
 
548
                    // IN:  number of elements in topology
 
549
                    xXineramaScreenInfo *displays,
 
550
                    // IN: array of display geometries
 
551
                    unsigned int width,
 
552
                    // IN: total width of topology
 
553
                    unsigned int height)
 
554
                    // IN: total height of topology
 
555
{
 
556
   ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
 
557
   int minWidth, minHeight, maxWidth, maxHeight;
 
558
   XRRScreenResources* xrrRes = NULL;
 
559
   XRROutputInfo** xrrOutputs;
 
560
   unsigned int numOutputs;
 
561
   unsigned int* outputMap;
 
562
   XRRCrtcInfo** xrrCrtcs;
 
563
   XRRScreenConfiguration* xrrConfig = NULL;
 
564
   XRRScreenSize* xrrSizes;
 
565
   Rotation xrrCurRotation;
 
566
   uint32 xrrNumSizes;
 
567
   SizeID currentSize;
 
568
   XRRModeInfo xrrModes[ndisplays];
 
569
   char name[RR12_MODE_MAXLEN];
 
570
   float dpi;
 
571
   int i, j, k;
 
572
   Bool success = FALSE;
 
573
 
 
574
   if (!XRRGetScreenSizeRange(resInfoX->display, resInfoX->rootWindow,
 
575
                              &minWidth, &minHeight, &maxWidth, &maxHeight) ||
 
576
       width < minWidth || height < minHeight ||
 
577
       width > maxWidth || height > maxHeight) {
 
578
      return FALSE;
 
579
   }
 
580
 
 
581
   /* Grab the server for two reasons:
 
582
    * - Avoid race conditions with other clients changing RandR configuration.
 
583
    * - Make our changes appear as atomic as possible to other clients.
 
584
    */
 
585
   XGrabServer(resInfoX->display);
 
586
 
 
587
   xrrRes = XRRGetScreenResources(resInfoX->display, resInfoX->rootWindow);
 
588
   if (!xrrRes) {
 
589
      goto error;
 
590
   }
 
591
 
 
592
   xrrCrtcs = Util_SafeCalloc(sizeof *xrrCrtcs, xrrRes->ncrtc);
 
593
   xrrOutputs = Util_SafeCalloc(sizeof *xrrOutputs, xrrRes->noutput);
 
594
   outputMap = Util_SafeCalloc(sizeof *outputMap, xrrRes->noutput);
 
595
 
 
596
   /* RandR may enumerate outputs differently from the host. Apply the nth
 
597
    * topology rectangle to the output called LVDS<n>.
 
598
    */
 
599
   for (i = 0; i < xrrRes->noutput; i++) {
 
600
      outputMap[i] = i;
 
601
   }
 
602
 
 
603
   numOutputs = 0;
 
604
   for (i = 0; i < xrrRes->noutput; i++) {
 
605
      unsigned int num;
 
606
 
 
607
      xrrOutputs[i] = XRRGetOutputInfo(resInfoX->display, xrrRes,
 
608
                                       xrrRes->outputs[i]);
 
609
 
 
610
      if (!xrrOutputs[i]) {
 
611
         goto error;
 
612
      }
 
613
 
 
614
      if (sscanf(xrrOutputs[i]->name, RR12_OUTPUT_FORMAT, &num) != 1 ||
 
615
          num > ndisplays) {
 
616
         continue;
 
617
      }
 
618
 
 
619
      outputMap[num - 1] = i;
 
620
 
 
621
      if (num > numOutputs) {
 
622
         numOutputs = num;
 
623
      }
 
624
   }
 
625
 
 
626
   /* Disable any CRTCs which won't be used or wont't fit in new screen size. */
 
627
   for (i = 0; i < xrrRes->ncrtc; i++) {
 
628
      xrrCrtcs[i] = XRRGetCrtcInfo(resInfoX->display, xrrRes,
 
629
                                   xrrRes->crtcs[i]);
 
630
 
 
631
      if (!xrrCrtcs[i]) {
 
632
         goto error;
 
633
      }
 
634
 
 
635
      for (j = 0; j < numOutputs; j++) {
 
636
         if (xrrOutputs[outputMap[j]]->crtc == xrrRes->crtcs[i]) {
 
637
            break;
 
638
         }
 
639
      }
 
640
 
 
641
      if (xrrCrtcs[i]->mode == None ||
 
642
          (j < numOutputs &&
 
643
           (xrrCrtcs[i]->x + xrrCrtcs[i]->width) <= width &&
 
644
           (xrrCrtcs[i]->y + xrrCrtcs[i]->height) <= height)) {
 
645
         continue;
 
646
      }
 
647
 
 
648
      if (XRRSetCrtcConfig(resInfoX->display, xrrRes, xrrRes->crtcs[i],
 
649
                           xrrCrtcs[i]->timestamp, 0, 0, None, RR_Rotate_0, NULL, 0)
 
650
          != Success) {
 
651
         goto error;
 
652
      }
 
653
   }
 
654
 
 
655
   /* Set new screen size. */
 
656
   xrrConfig = XRRGetScreenInfo(resInfoX->display, resInfoX->rootWindow);
 
657
   xrrSizes = XRRConfigSizes(xrrConfig, &xrrNumSizes);
 
658
   currentSize = XRRConfigCurrentConfiguration(xrrConfig, &xrrCurRotation);
 
659
 
 
660
   if (xrrSizes[currentSize].mheight > 0) {
 
661
      dpi = MILLIS_PER_INCH * xrrSizes[currentSize].height / xrrSizes[currentSize].mheight;
 
662
 
 
663
      if (!dpi) {
 
664
         dpi = RR12_DEFAULT_DPI;
 
665
      }
 
666
   } else {
 
667
      dpi = RR12_DEFAULT_DPI;
 
668
   }
 
669
 
 
670
   XRRSetScreenSize(resInfoX->display, resInfoX->rootWindow, width, height,
 
671
                    (MILLIS_PER_INCH * width) / dpi,
 
672
                    (MILLIS_PER_INCH * height) / dpi);
 
673
 
 
674
   /* Set new topology. */
 
675
   for (i = 0; i < numOutputs; i++) {
 
676
      memset(xrrModes + i, 0, sizeof xrrModes[0]);
 
677
 
 
678
      xrrModes[i].width = displays[i].width;
 
679
      xrrModes[i].height = displays[i].height;
 
680
 
 
681
      /* Look for existing matching autofit mode. */
 
682
      for (j = 0; j < i && !xrrModes[i].id; j++) {
 
683
         if (xrrModes[j].id &&
 
684
             xrrModes[j].width == displays[i].width &&
 
685
             xrrModes[j].height == displays[i].height) {
 
686
            xrrModes[i].id = xrrModes[j].id;
 
687
            break;
 
688
         }
 
689
      }
 
690
 
 
691
      for (j = 0; j < xrrRes->nmode && !xrrModes[i].id; j++) {
 
692
         unsigned int w, h;
 
693
 
 
694
         if (sscanf(xrrRes->modes[j].name, RR12_MODE_FORMAT, &w, &h) == 2 &&
 
695
             w == displays[i].width && h == displays[i].height) {
 
696
            xrrModes[i].id = xrrRes->modes[j].id;
 
697
            break;
 
698
         }
 
699
      }
 
700
 
 
701
      /* If no luck, create new autofit mode. */
 
702
      if (!xrrModes[i].id) {
 
703
         sprintf(name, RR12_MODE_FORMAT, displays[i].width,
 
704
                 displays[i].height);
 
705
         xrrModes[i].name = name;
 
706
         xrrModes[i].nameLength = strlen(xrrModes[i].name);
 
707
         xrrModes[i].id = XRRCreateMode(resInfoX->display, resInfoX->rootWindow,
 
708
                                        xrrModes + i);
 
709
      }
 
710
 
 
711
      if (xrrModes[i].id == None) {
 
712
         continue;
 
713
      }
 
714
 
 
715
      /* Set autofit mode. */
 
716
      if (xrrOutputs[outputMap[i]]->crtc == None) {
 
717
         xrrOutputs[outputMap[i]]->crtc = xrrOutputs[outputMap[i]]->crtcs[0];
 
718
      }
 
719
 
 
720
      for (j = 0; j < xrrOutputs[outputMap[i]]->nmode; j++) {
 
721
         if (xrrModes[i].id == xrrOutputs[outputMap[i]]->modes[j]) {
 
722
            break;
 
723
         }
 
724
      }
 
725
      if (j == xrrOutputs[outputMap[i]]->nmode) {
 
726
         XRRAddOutputMode(resInfoX->display, xrrRes->outputs[outputMap[i]],
 
727
                          xrrModes[i].id);
 
728
      }
 
729
      if (XRRSetCrtcConfig(resInfoX->display, xrrRes,
 
730
                           xrrOutputs[outputMap[i]]->crtc, xrrCrtcs[i]->timestamp,
 
731
                           displays[i].x_org, displays[i].y_org, xrrModes[i].id,
 
732
                           RR_Rotate_0, xrrRes->outputs + outputMap[i], 1)
 
733
          != Success) {
 
734
         goto error;
 
735
      }
 
736
   }
 
737
 
 
738
   /* Delete unused autofit modes. */
 
739
   for (i = 0; i < xrrRes->nmode; i++) {
 
740
      unsigned int w, h;
 
741
      Bool destroy = TRUE;
 
742
 
 
743
      if (sscanf(xrrRes->modes[i].name, RR12_MODE_FORMAT, &w, &h) != 2) {
 
744
         continue;
 
745
      }
 
746
 
 
747
      for (j = 0; j < xrrRes->noutput; j++) {
 
748
         if (j < numOutputs &&
 
749
             w == displays[j].width && h == displays[j].height) {
 
750
            destroy = FALSE;
 
751
            continue;
 
752
         }
 
753
 
 
754
         for (k = 0; k < xrrOutputs[outputMap[j]]->nmode; k++) {
 
755
            if (xrrOutputs[outputMap[j]]->modes[k] == xrrRes->modes[i].id) {
 
756
               XRRDeleteOutputMode(resInfoX->display,
 
757
                                   xrrRes->outputs[outputMap[j]],
 
758
                                   xrrOutputs[outputMap[j]]->modes[k]);
 
759
               break;
 
760
            }
 
761
         }
 
762
      }
 
763
 
 
764
      if (destroy) {
 
765
         XRRDestroyMode(resInfoX->display, xrrRes->modes[i].id);
 
766
      }
 
767
   }
 
768
 
 
769
   resInfoX->topologyDisplays = ndisplays;
 
770
   resInfoX->topologyWidth = width;
 
771
   resInfoX->topologyHeight = height;
 
772
 
 
773
   success = TRUE;
 
774
 
 
775
error:
 
776
   XUngrabServer(resInfoX->display);
 
777
 
 
778
   if (xrrConfig) {
 
779
      XRRFreeScreenConfigInfo(xrrConfig);
 
780
   }
 
781
   if (xrrRes) {
 
782
      for (i = 0; i < xrrRes->noutput; i++) {
 
783
         if (xrrOutputs[i]) {
 
784
            XRRFreeOutputInfo(xrrOutputs[i]);
 
785
         }
 
786
      }
 
787
      for (i = 0; i < xrrRes->ncrtc; i++) {
 
788
         if (xrrCrtcs[i]) {
 
789
            XRRFreeCrtcInfo(xrrCrtcs[i]);
 
790
         }
 
791
      }
 
792
      free(outputMap);
 
793
      free(xrrOutputs);
 
794
      free(xrrCrtcs);
 
795
      XRRFreeScreenResources(xrrRes);
 
796
   }
 
797
 
 
798
   return success;
 
799
}
 
800
 
 
801
#endif // ifndef NO_MULTIMON
450
802
 
451
803
 
452
804
/*-----------------------------------------------------------------------------
479
831
   uint64 bestFitSize = 0;
480
832
   uint64 potentialSize;
481
833
 
 
834
#ifndef NO_MULTIMON
 
835
   if (resInfoX->canUseRandR12) {
 
836
      if (resInfoX->topologyDisplays != 1 ||
 
837
          resInfoX->topologyWidth != width ||
 
838
          resInfoX->topologyHeight != height) {
 
839
         xXineramaScreenInfo display;
 
840
 
 
841
         display.x_org = 0;
 
842
         display.y_org = 0;
 
843
         display.width = width;
 
844
         display.height = height;
 
845
 
 
846
         return RandR12_SetTopology(1, &display, width, height);
 
847
      }
 
848
 
 
849
      return TRUE;
 
850
   }
 
851
#endif
 
852
 
482
853
   xrrConfig = XRRGetScreenInfo(resInfoX->display, resInfoX->rootWindow);
483
854
   xrrSizes = XRRConfigSizes(xrrConfig, &xrrNumSizes);
484
855
   XRRConfigCurrentConfiguration(xrrConfig, &xrrCurRotation);