~n-muench/ubuntu/oneiric/open-vm-tools/open-vm-tools.fix-836277

« back to all changes in this revision

Viewing changes to services/plugins/resolutionSet/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:
46
46
#include "libvmwarectrl.h"
47
47
#include "str.h"
48
48
#include "strutil.h"
 
49
#include "util.h"
49
50
 
50
51
#define VMWAREDRV_PATH_64   "/usr/X11R6/lib64/modules/drivers/vmware_drv.o"
51
52
#define VMWAREDRV_PATH      "/usr/X11R6/lib/modules/drivers/vmware_drv.o"
52
53
#define VERSION_STRING      "VMware Guest X Server"
53
54
 
 
55
#define RR12_OUTPUT_FORMAT "LVDS%u"
 
56
#define RR12_MODE_FORMAT "autofit-%ux%u"
 
57
#define RR12_MODE_MAXLEN (sizeof RR12_MODE_FORMAT + 2 * (10 - 2) + 1)
 
58
#define RR12_DEFAULT_DPI 96.0
 
59
#define MILLIS_PER_INCH 25.4
 
60
 
54
61
 
55
62
/**
56
63
 * Describes the state of the X11 back-end of lib/resolution.
62
69
                                // TRUE if VMwareCtrl extension available
63
70
   Bool         canUseVMwareCtrlTopologySet;
64
71
                                // TRUE if VMwareCtrl extension supports topology set
 
72
   Bool         canUseRandR12;  // TRUE if RandR extension >= 1.2 available
 
73
   unsigned int topologyDisplays;
 
74
                                // Number of displays in current topology
 
75
   unsigned int topologyWidth;  // Total width of current topology
 
76
   unsigned int topologyHeight; // Total height of current topology
65
77
} ResolutionInfoX11Type;
66
78
 
67
79
 
77
89
 
78
90
static Bool ResolutionCanSet(void);
79
91
static Bool TopologyCanSet(void);
 
92
#ifndef NO_MULTIMON
 
93
static Bool RandR12_SetTopology(unsigned int ndisplays,
 
94
                                xXineramaScreenInfo *displays,
 
95
                                unsigned int width, unsigned int height);
 
96
#endif
80
97
static Bool SelectResolution(uint32 width, uint32 height);
81
98
 
82
99
 
115
132
   resInfoX->canUseVMwareCtrl = VMwareCtrl_QueryVersion(resInfoX->display, &dummy1,
116
133
                                                        &dummy2);
117
134
   resInfoX->canUseVMwareCtrlTopologySet = FALSE;
 
135
   resInfoX->canUseRandR12 = FALSE;
118
136
 
119
137
   resInfo->canSetResolution = ResolutionCanSet();
120
138
   resInfo->canSetTopology = TopologyCanSet();
241
259
      displays[i].y_org -= minY;
242
260
   }
243
261
 
244
 
   if (!VMwareCtrl_SetTopology(resInfoX->display, DefaultScreen(resInfoX->display), displays,
245
 
                               ndisplays)) {
246
 
      Debug("Failed to set topology in the driver.\n");
247
 
      goto out;
248
 
   }
249
 
 
250
 
   if (!SelectResolution(maxX - minX, maxY - minY)) {
251
 
      Debug("Failed to set new resolution.\n");
252
 
      goto out;
253
 
   }
254
 
 
255
 
   success = TRUE;
 
262
   if (resInfoX->canUseVMwareCtrlTopologySet) {
 
263
      if (!VMwareCtrl_SetTopology(resInfoX->display, DefaultScreen(resInfoX->display),
 
264
                                  displays, ndisplays)) {
 
265
         Debug("Failed to set topology in the driver.\n");
 
266
         goto out;
 
267
      }
 
268
 
 
269
      if (!SelectResolution(maxX - minX, maxY - minY)) {
 
270
         Debug("Failed to set new resolution.\n");
 
271
         goto out;
 
272
      }
 
273
 
 
274
      success = TRUE;
 
275
   } else if (resInfoX->canUseRandR12) {
 
276
      success = RandR12_SetTopology(ndisplays, displays,
 
277
                                    maxX - minX, maxY - minY);
 
278
   }
256
279
 
257
280
out:
258
281
   free(displays);
299
322
      return TRUE;
300
323
   }
301
324
 
 
325
#ifndef NO_MULTIMON
 
326
   /* See if RandR >= 1.2 can be used: The extension version is high enough and
 
327
    * all output names match the expected format.
 
328
    */
 
329
   if (major > 1 || (major == 1 && minor >= 2)) {
 
330
      XRRScreenResources* xrrRes;
 
331
      XRROutputInfo* xrrOutput;
 
332
      unsigned int num;
 
333
      int i;
 
334
 
 
335
      XGrabServer(resInfoX->display);
 
336
 
 
337
      xrrRes = XRRGetScreenResources(resInfoX->display, resInfoX->rootWindow);
 
338
 
 
339
      if (xrrRes) {
 
340
         for (i = 0; i < xrrRes->noutput; i++) {
 
341
            xrrOutput = XRRGetOutputInfo(resInfoX->display, xrrRes,
 
342
                                         xrrRes->outputs[i]);
 
343
            if (!xrrOutput) {
 
344
               break;
 
345
            }
 
346
 
 
347
            if (sscanf(xrrOutput->name, RR12_OUTPUT_FORMAT, &num) != 1 ||
 
348
                num < 1) {
 
349
               XRRFreeOutputInfo(xrrOutput);
 
350
               break;
 
351
            }
 
352
 
 
353
            XRRFreeOutputInfo(xrrOutput);
 
354
         }
 
355
 
 
356
         if (i == xrrRes->noutput) {
 
357
            resInfoX->canUseRandR12 = TRUE;
 
358
         } else {
 
359
            Debug("RandR >= 1.2 not usable\n");
 
360
         }
 
361
 
 
362
         XRRFreeScreenResources(xrrRes);
 
363
      }
 
364
 
 
365
      XUngrabServer(resInfoX->display);
 
366
 
 
367
      if (resInfoX->canUseRandR12) {
 
368
         return TRUE;
 
369
      }
 
370
   }
 
371
#endif // ifndef NO_MULTIMON
 
372
 
302
373
   /*
303
374
    * XXX: This check does not work with XOrg 6.9/7.0 for two reasons: Both
304
375
    * versions now use .so for the driver extension and 7.0 moves the drivers
373
444
   ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
374
445
#ifdef NO_MULTIMON
375
446
   resInfoX->canUseVMwareCtrlTopologySet = FALSE;
 
447
   return FALSE;
376
448
#else
377
449
   int major;
378
450
   int minor;
379
451
 
 
452
   if (resInfoX->canUseRandR12) {
 
453
      return TRUE;
 
454
   }
 
455
 
380
456
   if (resInfoX->canUseVMwareCtrl && XineramaQueryVersion(resInfoX->display, &major,
381
457
                                                          &minor)) {
382
458
      /*
386
462
   } else {
387
463
      resInfoX->canUseVMwareCtrlTopologySet = FALSE;
388
464
   }
389
 
#endif
390
465
 
391
466
   return resInfoX->canUseVMwareCtrlTopologySet;
392
 
}
 
467
#endif
 
468
}
 
469
 
 
470
 
 
471
#ifndef NO_MULTIMON
 
472
 
 
473
/**
 
474
 * Employs the RandR 1.2 extension to set a new display topology.
 
475
 *
 
476
 * @return TRUE if operation succeeded, FALSE otherwise.
 
477
 */
 
478
 
 
479
static Bool
 
480
RandR12_SetTopology(unsigned int ndisplays,
 
481
                    // IN:  number of elements in topology
 
482
                    xXineramaScreenInfo *displays,
 
483
                    // IN: array of display geometries
 
484
                    unsigned int width,
 
485
                    // IN: total width of topology
 
486
                    unsigned int height)
 
487
                    // IN: total height of topology
 
488
{
 
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;
 
499
   uint32 xrrNumSizes;
 
500
   SizeID currentSize;
 
501
   XRRModeInfo xrrModes[ndisplays];
 
502
   char name[RR12_MODE_MAXLEN];
 
503
   float dpi;
 
504
   int i, j, k;
 
505
   Bool success = FALSE;
 
506
 
 
507
   if (!XRRGetScreenSizeRange(resInfoX->display, resInfoX->rootWindow,
 
508
                              &minWidth, &minHeight, &maxWidth, &maxHeight) ||
 
509
       width < minWidth || height < minHeight ||
 
510
       width > maxWidth || height > maxHeight) {
 
511
      return FALSE;
 
512
   }
 
513
 
 
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.
 
517
    */
 
518
   XGrabServer(resInfoX->display);
 
519
 
 
520
   xrrRes = XRRGetScreenResources(resInfoX->display, resInfoX->rootWindow);
 
521
   if (!xrrRes) {
 
522
      goto error;
 
523
   }
 
524
 
 
525
   xrrCrtcs = Util_SafeCalloc(sizeof *xrrCrtcs, xrrRes->ncrtc);
 
526
   xrrOutputs = Util_SafeCalloc(sizeof *xrrOutputs, xrrRes->noutput);
 
527
   outputMap = Util_SafeCalloc(sizeof *outputMap, xrrRes->noutput);
 
528
 
 
529
   /* RandR may enumerate outputs differently from the host. Apply the nth
 
530
    * topology rectangle to the output called LVDS<n>.
 
531
    */
 
532
   for (i = 0; i < xrrRes->noutput; i++) {
 
533
      outputMap[i] = i;
 
534
   }
 
535
 
 
536
   numOutputs = 0;
 
537
   for (i = 0; i < xrrRes->noutput; i++) {
 
538
      unsigned int num;
 
539
 
 
540
      xrrOutputs[i] = XRRGetOutputInfo(resInfoX->display, xrrRes,
 
541
                                       xrrRes->outputs[i]);
 
542
 
 
543
      if (!xrrOutputs[i]) {
 
544
         goto error;
 
545
      }
 
546
 
 
547
      if (sscanf(xrrOutputs[i]->name, RR12_OUTPUT_FORMAT, &num) != 1 ||
 
548
          num > ndisplays) {
 
549
         continue;
 
550
      }
 
551
 
 
552
      outputMap[num - 1] = i;
 
553
 
 
554
      if (num > numOutputs) {
 
555
         numOutputs = num;
 
556
      }
 
557
   }
 
558
 
 
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,
 
562
                                   xrrRes->crtcs[i]);
 
563
 
 
564
      if (!xrrCrtcs[i]) {
 
565
         goto error;
 
566
      }
 
567
 
 
568
      for (j = 0; j < numOutputs; j++) {
 
569
         if (xrrOutputs[outputMap[j]]->crtc == xrrRes->crtcs[i]) {
 
570
            break;
 
571
         }
 
572
      }
 
573
 
 
574
      if (xrrCrtcs[i]->mode == None ||
 
575
          (j < numOutputs &&
 
576
           (xrrCrtcs[i]->x + xrrCrtcs[i]->width) <= width &&
 
577
           (xrrCrtcs[i]->y + xrrCrtcs[i]->height) <= height)) {
 
578
         continue;
 
579
      }
 
580
 
 
581
      if (XRRSetCrtcConfig(resInfoX->display, xrrRes, xrrRes->crtcs[i],
 
582
                           xrrCrtcs[i]->timestamp, 0, 0, None, RR_Rotate_0, NULL, 0)
 
583
          != Success) {
 
584
         goto error;
 
585
      }
 
586
   }
 
587
 
 
588
   /* Set new screen size. */
 
589
   xrrConfig = XRRGetScreenInfo(resInfoX->display, resInfoX->rootWindow);
 
590
   xrrSizes = XRRConfigSizes(xrrConfig, &xrrNumSizes);
 
591
   currentSize = XRRConfigCurrentConfiguration(xrrConfig, &xrrCurRotation);
 
592
 
 
593
   if (xrrSizes[currentSize].mheight > 0) {
 
594
      dpi = MILLIS_PER_INCH * xrrSizes[currentSize].height / xrrSizes[currentSize].mheight;
 
595
 
 
596
      if (!dpi) {
 
597
         dpi = RR12_DEFAULT_DPI;
 
598
      }
 
599
   } else {
 
600
      dpi = RR12_DEFAULT_DPI;
 
601
   }
 
602
 
 
603
   XRRSetScreenSize(resInfoX->display, resInfoX->rootWindow, width, height,
 
604
                    (MILLIS_PER_INCH * width) / dpi,
 
605
                    (MILLIS_PER_INCH * height) / dpi);
 
606
 
 
607
   /* Set new topology. */
 
608
   for (i = 0; i < numOutputs; i++) {
 
609
      memset(xrrModes + i, 0, sizeof xrrModes[0]);
 
610
 
 
611
      xrrModes[i].width = displays[i].width;
 
612
      xrrModes[i].height = displays[i].height;
 
613
 
 
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;
 
620
            break;
 
621
         }
 
622
      }
 
623
 
 
624
      for (j = 0; j < xrrRes->nmode && !xrrModes[i].id; j++) {
 
625
         unsigned int w, h;
 
626
 
 
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;
 
630
            break;
 
631
         }
 
632
      }
 
633
 
 
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,
 
637
                     displays[i].height);
 
638
         xrrModes[i].name = name;
 
639
         xrrModes[i].nameLength = strlen(xrrModes[i].name);
 
640
         xrrModes[i].id = XRRCreateMode(resInfoX->display, resInfoX->rootWindow,
 
641
                                        xrrModes + i);
 
642
      }
 
643
 
 
644
      if (xrrModes[i].id == None) {
 
645
         continue;
 
646
      }
 
647
 
 
648
      /* Set autofit mode. */
 
649
      if (xrrOutputs[outputMap[i]]->crtc == None) {
 
650
         xrrOutputs[outputMap[i]]->crtc = xrrOutputs[outputMap[i]]->crtcs[0];
 
651
      }
 
652
 
 
653
      for (j = 0; j < xrrOutputs[outputMap[i]]->nmode; j++) {
 
654
         if (xrrModes[i].id == xrrOutputs[outputMap[i]]->modes[j]) {
 
655
            break;
 
656
         }
 
657
      }
 
658
      if (j == xrrOutputs[outputMap[i]]->nmode) {
 
659
         XRRAddOutputMode(resInfoX->display, xrrRes->outputs[outputMap[i]],
 
660
                          xrrModes[i].id);
 
661
      }
 
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)
 
666
          != Success) {
 
667
         goto error;
 
668
      }
 
669
   }
 
670
 
 
671
   /* Delete unused autofit modes. */
 
672
   for (i = 0; i < xrrRes->nmode; i++) {
 
673
      unsigned int w, h;
 
674
      Bool destroy = TRUE;
 
675
 
 
676
      if (sscanf(xrrRes->modes[i].name, RR12_MODE_FORMAT, &w, &h) != 2) {
 
677
         continue;
 
678
      }
 
679
 
 
680
      for (j = 0; j < xrrRes->noutput; j++) {
 
681
         if (j < numOutputs &&
 
682
             w == displays[j].width && h == displays[j].height) {
 
683
            destroy = FALSE;
 
684
            continue;
 
685
         }
 
686
 
 
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]);
 
692
               break;
 
693
            }
 
694
         }
 
695
      }
 
696
 
 
697
      if (destroy) {
 
698
         XRRDestroyMode(resInfoX->display, xrrRes->modes[i].id);
 
699
      }
 
700
   }
 
701
 
 
702
   resInfoX->topologyDisplays = ndisplays;
 
703
   resInfoX->topologyWidth = width;
 
704
   resInfoX->topologyHeight = height;
 
705
 
 
706
   success = TRUE;
 
707
 
 
708
error:
 
709
   XUngrabServer(resInfoX->display);
 
710
 
 
711
   if (xrrConfig) {
 
712
      XRRFreeScreenConfigInfo(xrrConfig);
 
713
   }
 
714
   if (xrrRes) {
 
715
      for (i = 0; i < xrrRes->noutput; i++) {
 
716
         if (xrrOutputs[i]) {
 
717
            XRRFreeOutputInfo(xrrOutputs[i]);
 
718
         }
 
719
      }
 
720
      for (i = 0; i < xrrRes->ncrtc; i++) {
 
721
         if (xrrCrtcs[i]) {
 
722
            XRRFreeCrtcInfo(xrrCrtcs[i]);
 
723
         }
 
724
      }
 
725
      free(outputMap);
 
726
      free(xrrOutputs);
 
727
      free(xrrCrtcs);
 
728
      XRRFreeScreenResources(xrrRes);
 
729
   }
 
730
 
 
731
   return success;
 
732
}
 
733
 
 
734
#endif // ifndef NO_MULTIMON
393
735
 
394
736
 
395
737
/**
415
757
   uint64 bestFitSize = 0;
416
758
   uint64 potentialSize;
417
759
 
 
760
#ifndef NO_MULTIMON
 
761
   if (resInfoX->canUseRandR12) {
 
762
      if (resInfoX->topologyDisplays != 1 ||
 
763
          resInfoX->topologyWidth != width ||
 
764
          resInfoX->topologyHeight != height) {
 
765
         xXineramaScreenInfo display;
 
766
 
 
767
         display.x_org = 0;
 
768
         display.y_org = 0;
 
769
         display.width = width;
 
770
         display.height = height;
 
771
 
 
772
         return RandR12_SetTopology(1, &display, width, height);
 
773
      }
 
774
 
 
775
      return TRUE;
 
776
   }
 
777
#endif
 
778
 
418
779
   xrrConfig = XRRGetScreenInfo(resInfoX->display, resInfoX->rootWindow);
419
780
   xrrSizes = XRRConfigSizes(xrrConfig, &xrrNumSizes);
420
781
   XRRConfigCurrentConfiguration(xrrConfig, &xrrCurRotation);