~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to services/plugins/resolutionSet/resolutionX11.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#include <string.h>
28
28
 
29
29
#include "resolutionInt.h"
 
30
#include "resolutionRandR12.h"
30
31
 
31
32
#include <X11/Xlib.h>
32
33
#include <X11/extensions/Xrandr.h>
53
54
#define VMWAREDRV_PATH      "/usr/X11R6/lib/modules/drivers/vmware_drv.o"
54
55
#define VERSION_STRING      "VMware Guest X Server"
55
56
 
56
 
#define RR12_OUTPUT_FORMAT "LVDS%u"
57
 
#define RR12_MODE_FORMAT "autofit-%ux%u"
58
 
#define RR12_MODE_MAXLEN (sizeof RR12_MODE_FORMAT + 2 * (10 - 2) + 1)
59
 
#define RR12_DEFAULT_DPI 96.0
60
 
#define MILLIS_PER_INCH 25.4
61
 
 
62
 
 
63
57
/**
64
58
 * Describes the state of the X11 back-end of lib/resolution.
65
59
 */
71
65
   Bool         canUseVMwareCtrlTopologySet;
72
66
                                // TRUE if VMwareCtrl extension supports topology set
73
67
   Bool         canUseRandR12;  // TRUE if RandR extension >= 1.2 available
74
 
   unsigned int topologyDisplays;
75
 
                                // Number of displays in current topology
76
 
   unsigned int topologyWidth;  // Total width of current topology
77
 
   unsigned int topologyHeight; // Total height of current topology
78
68
} ResolutionInfoX11Type;
79
69
 
80
70
 
90
80
 
91
81
static Bool ResolutionCanSet(void);
92
82
static Bool TopologyCanSet(void);
93
 
#ifndef NO_MULTIMON
94
 
static Bool RandR12_SetTopology(unsigned int ndisplays,
95
 
                                xXineramaScreenInfo *displays,
96
 
                                unsigned int width, unsigned int height);
97
 
#endif
98
83
static Bool SelectResolution(uint32 width, uint32 height);
99
84
 
100
85
 
171
156
   ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
172
157
   ASSERT(resolutionInfo.canSetResolution);
173
158
 
174
 
   if (resInfoX->canUseVMwareCtrl) {
 
159
   if (resInfoX->canUseVMwareCtrl && !resInfoX->canUseRandR12) {
175
160
      /*
176
161
       * If so, use the VMWARE_CTRL extension to provide a custom resolution
177
162
       * which we'll find as an exact match from XRRConfigSizes() (unless
181
166
       * effort attempt to change resolution anyway.
182
167
       */
183
168
      VMwareCtrl_SetRes(resInfoX->display, DefaultScreen(resInfoX->display),
184
 
                        width, height);
 
169
                        width, height);
185
170
   }
186
171
 
187
172
   return SelectResolution(width, height);
214
199
   xXineramaScreenInfo *displays = NULL;
215
200
   short maxX = 0;
216
201
   short maxY = 0;
217
 
   int minX = 0;
218
 
   int minY = 0;
 
202
   int minX = 0x7FFF;
 
203
   int minY = 0x7FFF;
219
204
 
220
205
   ASSERT(resolutionInfo.canSetTopology);
221
206
 
260
245
      displays[i].y_org -= minY;
261
246
   }
262
247
 
263
 
   if (resInfoX->canUseVMwareCtrlTopologySet) {
 
248
   if (resInfoX->canUseRandR12) {
 
249
      success = RandR12_SetTopology(resInfoX->display,
 
250
                                    DefaultScreen(resInfoX->display),
 
251
                                    resInfoX->rootWindow,
 
252
                                    ndisplays, displays,
 
253
                                    maxX - minX, maxY - minY);
 
254
   } else if (resInfoX->canUseVMwareCtrlTopologySet) {
264
255
      if (!VMwareCtrl_SetTopology(resInfoX->display, DefaultScreen(resInfoX->display),
265
256
                                  displays, ndisplays)) {
266
257
         g_debug("Failed to set topology in the driver.\n");
273
264
      }
274
265
 
275
266
      success = TRUE;
276
 
   } else if (resInfoX->canUseRandR12) {
277
 
      success = RandR12_SetTopology(ndisplays, displays,
278
 
                                    maxX - minX, maxY - minY);
279
267
   }
280
268
 
281
269
out:
291
279
 
292
280
 
293
281
/**
294
 
 * Is the VMware SVGA driver a high enough version to support resolution
295
 
 * changing? We check by searching the driver binary for a known version
296
 
 * string.
 
282
 * Does VMware SVGA driver support resolution changing? We check by
 
283
 * testing RandR version and the availability of VMWCTRL extension. It
 
284
 * also check the output names for RandR 1.2 and above which is used for
 
285
 * the vmwgfx driver. Finally it searches the driver binary for a known
 
286
 * version string.
 
287
 *
 
288
 * resInfoX->canUseRandR12 will be set if RandR12 is usable.
297
289
 *
298
290
 * @return TRUE if the driver version is high enough, FALSE otherwise.
299
291
 */
318
310
      return FALSE;
319
311
   }
320
312
 
321
 
   /* See if the VMWARE_CTRL extension is supported */
322
 
   if (resInfoX->canUseVMwareCtrl) {
323
 
      return TRUE;
324
 
   }
325
 
 
326
313
#ifndef NO_MULTIMON
327
 
   /* See if RandR >= 1.2 can be used: The extension version is high enough and
 
314
   /*
 
315
    * See if RandR >= 1.2 can be used: The extension version is high enough and
328
316
    * all output names match the expected format.
329
317
    */
330
318
   if (major > 1 || (major == 1 && minor >= 2)) {
369
357
         return TRUE;
370
358
      }
371
359
   }
 
360
 
372
361
#endif // ifndef NO_MULTIMON
373
362
 
374
363
   /*
 
364
    * See if the VMWARE_CTRL extension is supported.
 
365
    */
 
366
 
 
367
   if (resInfoX->canUseVMwareCtrl) {
 
368
      return TRUE;
 
369
   }
 
370
 
 
371
   /*
375
372
    * XXX: This check does not work with XOrg 6.9/7.0 for two reasons: Both
376
373
    * versions now use .so for the driver extension and 7.0 moves the drivers
377
374
    * to a completely different directory. As long as we ship a driver for
378
375
    * 6.9/7.0, we can instead just use the VMWARE_CTRL check.
379
376
    */
 
377
 
380
378
   buf[sizeof buf - 1] = '\0';
381
379
   FileIO_Invalidate(&fd);
382
380
   res = FileIO_Open(&fd, VMWAREDRV_PATH_64, FILEIO_ACCESS_READ, FILEIO_OPEN);
435
433
/**
436
434
 * Tests whether or not we can change display topology.
437
435
 *
 
436
 * resInfoX->canUseVMwareCtrlTopologySet will be set to TRUE if we should
 
437
 * use the old driver path when setting topology.
 
438
 *
438
439
 * @return TRUE if we're able to reset topology, otherwise FALSE.
439
440
 * @note resInfoX->canUseVMwareCtrlTopologySet will be set to TRUE on success.
440
441
 */
443
444
TopologyCanSet(void)
444
445
{
445
446
   ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
 
447
 
 
448
   /**
 
449
    * Note: For some strange reason, an early call to XineramaQueryVersion in
 
450
    * in this function stops vmtoolsd from deadlocking and freezing the X
 
451
    * display. Might be a call to XGrabServer() in and X library init
 
452
    * function that is called when we've already grabbed the server....
 
453
    */
 
454
 
446
455
#ifdef NO_MULTIMON
447
456
   resInfoX->canUseVMwareCtrlTopologySet = FALSE;
448
457
   return FALSE;
450
459
   int major;
451
460
   int minor;
452
461
 
453
 
   if (resInfoX->canUseRandR12) {
454
 
      return TRUE;
455
 
   }
456
 
 
457
462
   if (resInfoX->canUseVMwareCtrl && XineramaQueryVersion(resInfoX->display, &major,
458
463
                                                          &minor)) {
459
464
      /*
464
469
      resInfoX->canUseVMwareCtrlTopologySet = FALSE;
465
470
   }
466
471
 
467
 
   return resInfoX->canUseVMwareCtrlTopologySet;
 
472
   return resInfoX->canUseVMwareCtrlTopologySet || resInfoX->canUseRandR12;
468
473
#endif
469
474
}
470
475
 
471
 
 
472
 
#ifndef NO_MULTIMON
473
 
 
474
 
/**
475
 
 * Employs the RandR 1.2 extension to set a new display topology.
476
 
 *
477
 
 * @return TRUE if operation succeeded, FALSE otherwise.
478
 
 */
479
 
 
480
 
static Bool
481
 
RandR12_SetTopology(unsigned int ndisplays,
482
 
                    // IN:  number of elements in topology
483
 
                    xXineramaScreenInfo *displays,
484
 
                    // IN: array of display geometries
485
 
                    unsigned int width,
486
 
                    // IN: total width of topology
487
 
                    unsigned int height)
488
 
                    // IN: total height of topology
489
 
{
490
 
   ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
491
 
   int minWidth, minHeight, maxWidth, maxHeight;
492
 
   XRRScreenResources* xrrRes = NULL;
493
 
   XRROutputInfo** xrrOutputs;
494
 
   unsigned int numOutputs;
495
 
   unsigned int* outputMap;
496
 
   XRRCrtcInfo** xrrCrtcs;
497
 
   XRRScreenConfiguration* xrrConfig = NULL;
498
 
   XRRScreenSize* xrrSizes;
499
 
   Rotation xrrCurRotation;
500
 
   uint32 xrrNumSizes;
501
 
   SizeID currentSize;
502
 
   XRRModeInfo xrrModes[ndisplays];
503
 
   char name[RR12_MODE_MAXLEN];
504
 
   float dpi;
505
 
   int i, j, k;
506
 
   Bool success = FALSE;
507
 
 
508
 
   if (!XRRGetScreenSizeRange(resInfoX->display, resInfoX->rootWindow,
509
 
                              &minWidth, &minHeight, &maxWidth, &maxHeight) ||
510
 
       width < minWidth || height < minHeight ||
511
 
       width > maxWidth || height > maxHeight) {
512
 
      return FALSE;
513
 
   }
514
 
 
515
 
   /* Grab the server for two reasons:
516
 
    * - Avoid race conditions with other clients changing RandR configuration.
517
 
    * - Make our changes appear as atomic as possible to other clients.
518
 
    */
519
 
   XGrabServer(resInfoX->display);
520
 
 
521
 
   xrrRes = XRRGetScreenResources(resInfoX->display, resInfoX->rootWindow);
522
 
   if (!xrrRes) {
523
 
      goto error;
524
 
   }
525
 
 
526
 
   xrrCrtcs = Util_SafeCalloc(sizeof *xrrCrtcs, xrrRes->ncrtc);
527
 
   xrrOutputs = Util_SafeCalloc(sizeof *xrrOutputs, xrrRes->noutput);
528
 
   outputMap = Util_SafeCalloc(sizeof *outputMap, xrrRes->noutput);
529
 
 
530
 
   /* RandR may enumerate outputs differently from the host. Apply the nth
531
 
    * topology rectangle to the output called LVDS<n>.
532
 
    */
533
 
   for (i = 0; i < xrrRes->noutput; i++) {
534
 
      outputMap[i] = i;
535
 
   }
536
 
 
537
 
   numOutputs = 0;
538
 
   for (i = 0; i < xrrRes->noutput; i++) {
539
 
      unsigned int num;
540
 
 
541
 
      xrrOutputs[i] = XRRGetOutputInfo(resInfoX->display, xrrRes,
542
 
                                       xrrRes->outputs[i]);
543
 
 
544
 
      if (!xrrOutputs[i]) {
545
 
         goto error;
546
 
      }
547
 
 
548
 
      if (sscanf(xrrOutputs[i]->name, RR12_OUTPUT_FORMAT, &num) != 1 ||
549
 
          num > ndisplays) {
550
 
         continue;
551
 
      }
552
 
 
553
 
      outputMap[num - 1] = i;
554
 
 
555
 
      if (num > numOutputs) {
556
 
         numOutputs = num;
557
 
      }
558
 
   }
559
 
 
560
 
   /* Disable any CRTCs which won't be used or wont't fit in new screen size. */
561
 
   for (i = 0; i < xrrRes->ncrtc; i++) {
562
 
      xrrCrtcs[i] = XRRGetCrtcInfo(resInfoX->display, xrrRes,
563
 
                                   xrrRes->crtcs[i]);
564
 
 
565
 
      if (!xrrCrtcs[i]) {
566
 
         goto error;
567
 
      }
568
 
 
569
 
      for (j = 0; j < numOutputs; j++) {
570
 
         if (xrrOutputs[outputMap[j]]->crtc == xrrRes->crtcs[i]) {
571
 
            break;
572
 
         }
573
 
      }
574
 
 
575
 
      if (xrrCrtcs[i]->mode == None ||
576
 
          (j < numOutputs &&
577
 
           (xrrCrtcs[i]->x + xrrCrtcs[i]->width) <= width &&
578
 
           (xrrCrtcs[i]->y + xrrCrtcs[i]->height) <= height)) {
579
 
         continue;
580
 
      }
581
 
 
582
 
      if (XRRSetCrtcConfig(resInfoX->display, xrrRes, xrrRes->crtcs[i],
583
 
                           xrrCrtcs[i]->timestamp, 0, 0, None, RR_Rotate_0, NULL, 0)
584
 
          != Success) {
585
 
         goto error;
586
 
      }
587
 
   }
588
 
 
589
 
   /* Set new screen size. */
590
 
   xrrConfig = XRRGetScreenInfo(resInfoX->display, resInfoX->rootWindow);
591
 
   xrrSizes = XRRConfigSizes(xrrConfig, &xrrNumSizes);
592
 
   currentSize = XRRConfigCurrentConfiguration(xrrConfig, &xrrCurRotation);
593
 
 
594
 
   if (xrrSizes[currentSize].mheight > 0) {
595
 
      dpi = MILLIS_PER_INCH * xrrSizes[currentSize].height / xrrSizes[currentSize].mheight;
596
 
 
597
 
      if (!dpi) {
598
 
         dpi = RR12_DEFAULT_DPI;
599
 
      }
600
 
   } else {
601
 
      dpi = RR12_DEFAULT_DPI;
602
 
   }
603
 
 
604
 
   XRRSetScreenSize(resInfoX->display, resInfoX->rootWindow, width, height,
605
 
                    (MILLIS_PER_INCH * width) / dpi,
606
 
                    (MILLIS_PER_INCH * height) / dpi);
607
 
 
608
 
   /* Set new topology. */
609
 
   for (i = 0; i < numOutputs; i++) {
610
 
      memset(xrrModes + i, 0, sizeof xrrModes[0]);
611
 
 
612
 
      xrrModes[i].width = displays[i].width;
613
 
      xrrModes[i].height = displays[i].height;
614
 
 
615
 
      /* Look for existing matching autofit mode. */
616
 
      for (j = 0; j < i && !xrrModes[i].id; j++) {
617
 
         if (xrrModes[j].id &&
618
 
             xrrModes[j].width == displays[i].width &&
619
 
             xrrModes[j].height == displays[i].height) {
620
 
            xrrModes[i].id = xrrModes[j].id;
621
 
            break;
622
 
         }
623
 
      }
624
 
 
625
 
      for (j = 0; j < xrrRes->nmode && !xrrModes[i].id; j++) {
626
 
         unsigned int w, h;
627
 
 
628
 
         if (sscanf(xrrRes->modes[j].name, RR12_MODE_FORMAT, &w, &h) == 2 &&
629
 
             w == displays[i].width && h == displays[i].height) {
630
 
            xrrModes[i].id = xrrRes->modes[j].id;
631
 
            break;
632
 
         }
633
 
      }
634
 
 
635
 
      /* If no luck, create new autofit mode. */
636
 
      if (!xrrModes[i].id) {
637
 
         Str_Sprintf(name, sizeof name, RR12_MODE_FORMAT, displays[i].width,
638
 
                     displays[i].height);
639
 
         xrrModes[i].name = name;
640
 
         xrrModes[i].nameLength = strlen(xrrModes[i].name);
641
 
         xrrModes[i].id = XRRCreateMode(resInfoX->display, resInfoX->rootWindow,
642
 
                                        xrrModes + i);
643
 
      }
644
 
 
645
 
      if (xrrModes[i].id == None) {
646
 
         continue;
647
 
      }
648
 
 
649
 
      /* Set autofit mode. */
650
 
      if (xrrOutputs[outputMap[i]]->crtc == None) {
651
 
         xrrOutputs[outputMap[i]]->crtc = xrrOutputs[outputMap[i]]->crtcs[0];
652
 
      }
653
 
 
654
 
      for (j = 0; j < xrrOutputs[outputMap[i]]->nmode; j++) {
655
 
         if (xrrModes[i].id == xrrOutputs[outputMap[i]]->modes[j]) {
656
 
            break;
657
 
         }
658
 
      }
659
 
      if (j == xrrOutputs[outputMap[i]]->nmode) {
660
 
         XRRAddOutputMode(resInfoX->display, xrrRes->outputs[outputMap[i]],
661
 
                          xrrModes[i].id);
662
 
      }
663
 
      if (XRRSetCrtcConfig(resInfoX->display, xrrRes,
664
 
                           xrrOutputs[outputMap[i]]->crtc, xrrCrtcs[i]->timestamp,
665
 
                           displays[i].x_org, displays[i].y_org, xrrModes[i].id,
666
 
                           RR_Rotate_0, xrrRes->outputs + outputMap[i], 1)
667
 
          != Success) {
668
 
         goto error;
669
 
      }
670
 
   }
671
 
 
672
 
   /* Delete unused autofit modes. */
673
 
   for (i = 0; i < xrrRes->nmode; i++) {
674
 
      unsigned int w, h;
675
 
      Bool destroy = TRUE;
676
 
 
677
 
      if (sscanf(xrrRes->modes[i].name, RR12_MODE_FORMAT, &w, &h) != 2) {
678
 
         continue;
679
 
      }
680
 
 
681
 
      for (j = 0; j < xrrRes->noutput; j++) {
682
 
         if (j < numOutputs &&
683
 
             w == displays[j].width && h == displays[j].height) {
684
 
            destroy = FALSE;
685
 
            continue;
686
 
         }
687
 
 
688
 
         for (k = 0; k < xrrOutputs[outputMap[j]]->nmode; k++) {
689
 
            if (xrrOutputs[outputMap[j]]->modes[k] == xrrRes->modes[i].id) {
690
 
               XRRDeleteOutputMode(resInfoX->display,
691
 
                                   xrrRes->outputs[outputMap[j]],
692
 
                                   xrrOutputs[outputMap[j]]->modes[k]);
693
 
               break;
694
 
            }
695
 
         }
696
 
      }
697
 
 
698
 
      if (destroy) {
699
 
         XRRDestroyMode(resInfoX->display, xrrRes->modes[i].id);
700
 
      }
701
 
   }
702
 
 
703
 
   resInfoX->topologyDisplays = ndisplays;
704
 
   resInfoX->topologyWidth = width;
705
 
   resInfoX->topologyHeight = height;
706
 
 
707
 
   success = TRUE;
708
 
 
709
 
error:
710
 
   XUngrabServer(resInfoX->display);
711
 
 
712
 
   if (xrrConfig) {
713
 
      XRRFreeScreenConfigInfo(xrrConfig);
714
 
   }
715
 
   if (xrrRes) {
716
 
      for (i = 0; i < xrrRes->noutput; i++) {
717
 
         if (xrrOutputs[i]) {
718
 
            XRRFreeOutputInfo(xrrOutputs[i]);
719
 
         }
720
 
      }
721
 
      for (i = 0; i < xrrRes->ncrtc; i++) {
722
 
         if (xrrCrtcs[i]) {
723
 
            XRRFreeCrtcInfo(xrrCrtcs[i]);
724
 
         }
725
 
      }
726
 
      free(outputMap);
727
 
      free(xrrOutputs);
728
 
      free(xrrCrtcs);
729
 
      XRRFreeScreenResources(xrrRes);
730
 
   }
731
 
 
732
 
   return success;
733
 
}
734
 
 
735
 
#endif // ifndef NO_MULTIMON
736
 
 
737
 
 
738
476
/**
739
477
 * Given a width and height, find the biggest resolution that will "fit".
740
478
 * This is called as a result of the resolution set request from the vmx.
741
479
 *
742
 
 * @param[in] width 
 
480
 * @param[in] width
743
481
 * @param[in] height
 
482
 *
744
483
 * @return TRUE if we are able to set to the exact size requested, FALSE otherwise.
745
484
 */
746
485
 
760
499
 
761
500
#ifndef NO_MULTIMON
762
501
   if (resInfoX->canUseRandR12) {
763
 
      if (resInfoX->topologyDisplays != 1 ||
764
 
          resInfoX->topologyWidth != width ||
765
 
          resInfoX->topologyHeight != height) {
766
 
         xXineramaScreenInfo display;
767
 
 
768
 
         display.x_org = 0;
769
 
         display.y_org = 0;
770
 
         display.width = width;
771
 
         display.height = height;
772
 
 
773
 
         return RandR12_SetTopology(1, &display, width, height);
774
 
      }
775
 
 
776
 
      return TRUE;
 
502
      xXineramaScreenInfo display;
 
503
 
 
504
      display.x_org = 0;
 
505
      display.y_org = 0;
 
506
      display.width = width;
 
507
      display.height = height;
 
508
 
 
509
      return RandR12_SetTopology(resInfoX->display,
 
510
                                 DefaultScreen(resInfoX->display),
 
511
                                 resInfoX->rootWindow,
 
512
                                 1, &display, width, height);
777
513
   }
778
514
#endif
779
515