]> source.dussan.org Git - tigervnc.git/commitdiff
Redo the RandR code in Xvnc/libvnc to use the modern 1.2 API. The old
authorPierre Ossman <ossman@cendio.se>
Thu, 12 Jul 2012 11:31:42 +0000 (11:31 +0000)
committerPierre Ossman <ossman@cendio.se>
Thu, 12 Jul 2012 11:31:42 +0000 (11:31 +0000)
stuff was a bit buggy, and it didn't really allow us to move forward.
This commit temporarily removes the ability for the client to resize the
session. It will be readded for Xvnc in a later commit. libvnc will be
without that functionality for now, as it is very difficult to get right
there.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4931 3789f03b-4d11-0410-bbf8-ca57d06f2519

unix/xserver/hw/vnc/XserverDesktop.cc
unix/xserver/hw/vnc/XserverDesktop.h
unix/xserver/hw/vnc/vncHooks.cc
unix/xserver/hw/vnc/xf86vncModule.cc
unix/xserver/hw/vnc/xvnc.cc

index 5fc32c3a98a3c128eddb38cb50daaa938cc055ae..6b1c2d9d604cf2fb9b9dcc7f2d5fc315d094ecd6 100644 (file)
@@ -200,6 +200,8 @@ void XserverDesktop::unblockUpdates()
 
 void XserverDesktop::setFramebuffer(int w, int h, void* fbptr, int stride)
 {
+  ScreenSet layout;
+
   width_ = w;
   height_ = h;
 
@@ -217,7 +219,66 @@ void XserverDesktop::setFramebuffer(int w, int h, void* fbptr, int stride)
   data = (rdr::U8*)fbptr;
   stride_ = stride;
 
-  server->setPixelBuffer(this);
+  layout = computeScreenLayout();
+
+  server->setPixelBuffer(this, layout);
+}
+
+void XserverDesktop::refreshScreenLayout()
+{
+  server->setScreenLayout(computeScreenLayout());
+}
+
+ScreenSet XserverDesktop::computeScreenLayout()
+{
+  ScreenSet layout;
+
+#ifndef RANDR
+  layout.add_screen(Screen(0, 0, 0, pScreen->width, pScreen->height, 0));
+#else
+  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+  CrtcIdMap newIdMap;
+
+  for (int i = 0;i < rp->numCrtcs;i++) {
+      RRCrtcPtr crtc;
+
+      crtc = rp->crtcs[i];
+
+      /* Disabled? */
+      if (crtc->mode == NULL)
+          continue;
+
+      /* Known CRTC? */
+      if (crtcIdMap.count(crtc) == 1)
+        newIdMap[crtc] = crtcIdMap[crtc];
+      else {
+        rdr::U32 id;
+        CrtcIdMap::const_iterator iter;
+
+        while (true) {
+          id = rand();
+          for (iter = crtcIdMap.begin();iter != crtcIdMap.end();++iter) {
+            if (iter->second == id)
+              break;
+          }
+          if (iter == crtcIdMap.end())
+            break;
+        }
+
+        newIdMap[crtc] = id;
+      }
+
+      layout.add_screen(Screen(newIdMap[crtc], crtc->x, crtc->y,
+                               crtc->mode->mode.width,
+                               crtc->mode->mode.height,
+                               0));
+  }
+
+  /* Only keep the entries that are currently active */
+  crtcIdMap = newIdMap;
+#endif
+
+  return layout;
 }
 
 char* XserverDesktop::substitute(const char* varName)
@@ -727,100 +788,15 @@ void XserverDesktop::clientCutText(const char* str, int len)
   vncClientCutText(str, len);
 }
 
-#ifdef RANDR
+extern unsigned int vncSetScreenLayout(ScreenPtr pScreen,
+                                       int fb_width, int fb_height,
+                                       const rfb::ScreenSet& layout);
+
 unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
                                              const rfb::ScreenSet& layout)
 {
-  int               i;
-  Bool              ret;
-  RRScreenSizePtr   pSize;
-  RROutputPtr       output;
-  RRModePtr         mode;
-
-  // Make sure all RandR tables are properly populated
-#if XORG == 15
-  ret = RRGetInfo(pScreen);
-#else
-  ret = RRGetInfo(pScreen, FALSE);
-#endif
-  if (!ret)
-    return resultNoResources;
-
-  // Register a new size, or get a reference to the existing one
-  pSize = RRRegisterSize(pScreen, fb_width, fb_height,
-                         pScreen->mmWidth, pScreen->mmHeight);
-  if (!pSize) {
-    vlog.error("setScreenLayout: Could not get register new resolution");
-    return resultNoResources;
-  }
-  ret = RRRegisterRate(pScreen, pSize, 60);
-  if (!ret) {
-    vlog.error("setScreenLayout: Could not register a rate for the resolution");
-    return resultNoResources;
-  }
-
-  // Then we have to call RRGetInfo again for it to copy the RandR
-  // 1.0 information to the 1.2 structures.
-#if XORG == 15
-  ret = RRGetInfo(pScreen);
-#else
-  ret = RRGetInfo(pScreen, FALSE);
-#endif
-  if (!ret)
-    return resultNoResources;
-
-  // Go via RandR to set the resolution in order for X11 notifications
-  // to be sent out properly. We currently only do RandR 1.0, but Xorg
-  // has dropped support for that API. So we have to emulate it via the
-  // same method ProcRRSetScreenConfig() uses.
-  //
-  // FIXME: This will cause setPixelBuffer() to be called, resulting in
-  //        an unnecessary ExtendedDesktopSize to be sent.
-
-  // We'll just reconfigure the first output
-  output = RRFirstOutput(pScreen);
-  if (!output) {
-    vlog.error("setScreenLayout: Could not get first output");
-    return resultNoResources;
-  }
-
-  // Find first mode with matching size
-  mode = NULL;
-  for (i = 0;i < output->numModes;i++) {
-    if ((output->modes[i]->mode.width == fb_width) &&
-        (output->modes[i]->mode.height == fb_height)) {
-      mode = output->modes[i];
-      break;
-    }
-  }
-  if (!mode) {
-    vlog.error("setScreenLayout: Could not find a matching mode");
-    return resultNoResources;
-  }
-
-  // Adjust screen size
-  ret = RRScreenSizeSet(pScreen, fb_width, fb_height,
-                        pScreen->mmWidth, pScreen->mmHeight);
-  if (!ret) {
-    vlog.error("setScreenLayout: Could not adjust screen size");
-    return resultNoResources;
-  }
-
-  // And then the CRTC
-  ret = RRCrtcSet(output->crtc, mode, 0, 0, RR_Rotate_0, 1, &output);
-  if (!ret) {
-    vlog.error("setScreenLayout: Could not adjust CRTC");
-    return resultNoResources;
-  }
-
-  // RandR 1.0 doesn't carry any screen layout information, so we need
-  // to update that manually. This results in another unnecessary
-  // ExtendedDesktopSize.
-  server->setScreenLayout(layout);
-
-  return resultSuccess;
+  return vncSetScreenLayout(pScreen, fb_width, fb_height, layout);
 }
-#endif // RANDR
 
 void XserverDesktop::grabRegion(const rfb::Region& region)
 {
index 0aba4ef63f4e5dcc418b1f4c6ae26e19212c3bfd..4e9b99b8eecec675156a80de5a0e0ce1e4d3a8ce 100644 (file)
@@ -27,6 +27,8 @@
 #include <dix-config.h>
 #endif
 
+#include <map>
+
 #include <rfb/SDesktop.h>
 #include <rfb/HTTPServer.h>
 #include <rfb/PixelBuffer.h>
@@ -39,6 +41,9 @@ extern "C" {
 #define class c_class
 #include <scrnintstr.h>
 #include <os.h>
+#ifdef RANDR
+#include <randrstr.h>
+#endif
 #undef class
 }
 
@@ -64,6 +69,7 @@ public:
   void blockUpdates();
   void unblockUpdates();
   void setFramebuffer(int w, int h, void* fbptr, int stride);
+  void refreshScreenLayout();
   void setColormap(ColormapPtr cmap);
   void setColourMapEntries(ColormapPtr pColormap, int ndef, xColorItem* pdef);
   void bell();
@@ -101,10 +107,8 @@ public:
   virtual void keyEvent(rdr::U32 key, bool down);
   virtual void clientCutText(const char* str, int len);
   virtual rfb::Point getFbSize() { return rfb::Point(width(), height()); }
-#ifdef RANDR
   virtual unsigned int setScreenLayout(int fb_width, int fb_height,
                                        const rfb::ScreenSet& layout);
-#endif
 
   // rfb::PixelBuffer callbacks
   virtual void grabRegion(const rfb::Region& r);
@@ -123,6 +127,7 @@ public:
 
 private:
   void setColourMapEntries(int firstColour, int nColours);
+  rfb::ScreenSet computeScreenLayout();
   ScreenPtr pScreen;
   InputDevice *inputDevice;
   rfb::VNCServerST* server;
@@ -139,5 +144,10 @@ private:
   void* queryConnectId;
   rfb::CharArray queryConnectAddress;
   rfb::CharArray queryConnectUsername;
+
+#ifdef RANDR
+  typedef std::map<RRCrtcPtr, rdr::U32> CrtcIdMap;
+  CrtcIdMap crtcIdMap;
+#endif
 };
 #endif
index b03b6aa02abbe5ed091e4c6e6bd6d9b267abaa6a..e39a0f4f5433f2eaf98895d5c5d4514355945abc 100644 (file)
@@ -84,6 +84,8 @@ typedef struct {
 #endif
 #ifdef RANDR
   RRSetConfigProcPtr           RandRSetConfig;
+  RRScreenSetSizeProcPtr       RandRScreenSetSize;
+  RRCrtcSetProcPtr             RandRCrtcSet;
 #endif
 } vncHooksScreenRec, *vncHooksScreenPtr;
 
@@ -143,6 +145,13 @@ static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
 #ifdef RANDR
 static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
                                    int rate, RRScreenSizePtr pSize);
+static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
+                                       CARD16 width, CARD16 height,
+                                       CARD32 mmWidth, CARD32 mmHeight);
+static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
+                                 RRModePtr mode, int x, int y,
+                                 Rotation rotation, int numOutputs,
+                                 RROutputPtr *outputs);
 #endif
 
 // GC "funcs"
@@ -283,6 +292,8 @@ Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop)
   rp = rrGetScrPriv(pScreen);
   if (rp) {
     vncHooksScreen->RandRSetConfig = rp->rrSetConfig;
+    vncHooksScreen->RandRScreenSetSize = rp->rrScreenSetSize;
+    vncHooksScreen->RandRCrtcSet = rp->rrCrtcSet;
   }
 #endif
 
@@ -304,7 +315,13 @@ Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop)
 #endif
 #ifdef RANDR
   if (rp) {
-    rp->rrSetConfig = vncHooksRandRSetConfig;
+    /* Some RandR callbacks are optional */
+    if (rp->rrSetConfig)
+      rp->rrSetConfig = vncHooksRandRSetConfig;
+    if (rp->rrScreenSetSize)
+      rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
+    if (rp->rrCrtcSet)
+      rp->rrCrtcSet = vncHooksRandRCrtcSet;
   }
 #endif
 
@@ -361,6 +378,8 @@ static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_)
   rp = rrGetScrPriv(pScreen);
   if (rp) {
     rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
+    rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
+    rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
   }
 #endif
 
@@ -596,42 +615,106 @@ void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
 
 #ifdef RANDR
 
+static void vncPreScreenResize(ScreenPtr pScreen)
+{
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+
+  // We need to prevent the RFB core from accessing the framebuffer
+  // for a while as there might be updates thrown our way inside
+  // the routines that change the screen (i.e. before we have a
+  // pointer to the new framebuffer).
+  vncHooksScreen->desktop->blockUpdates();
+}
+
+static void vncPostScreenResize(ScreenPtr pScreen, Bool success)
+{
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+
+  RegionRec reg;
+  BoxRec box;
+
+  if (success) {
+    // Let the RFB core know of the new dimensions and framebuffer
+    vncHooksScreen->desktop->setFramebuffer(pScreen->width, pScreen->height,
+                                            vncFbptr[pScreen->myNum],
+                                            vncFbstride[pScreen->myNum]);
+  }
+
+  vncHooksScreen->desktop->unblockUpdates();
+
+  if (success) {
+    // Mark entire screen as changed
+    box.x1 = 0;
+    box.y1 = 0;
+    box.x2 = pScreen->width;
+    box.y2 = pScreen->height;
+    REGION_INIT(pScreen, &reg, &box, 1);
+
+    vncHooksScreen->desktop->add_changed(&reg);
+  }
+}
+
 static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
                                    int rate, RRScreenSizePtr pSize)
 {
   vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
   rrScrPrivPtr rp = rrGetScrPriv(pScreen);
   Bool ret;
-  RegionRec reg;
-  BoxRec box;
 
-  // We need to prevent the RFB core from accessing the framebuffer
-  // for a while as there might be updates thrown our way inside
-  // rrSetConfig (i.e. before we have a pointer to the new framebuffer).
-  vncHooksScreen->desktop->blockUpdates();
+  vncPreScreenResize(pScreen);
 
   rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
   ret = (*rp->rrSetConfig)(pScreen, rotation, rate, pSize);
   rp->rrSetConfig = vncHooksRandRSetConfig;
 
+  vncPostScreenResize(pScreen, ret);
+
   if (!ret)
     return FALSE;
 
-  // Let the RFB core know of the new dimensions and framebuffer
-  vncHooksScreen->desktop->setFramebuffer(pScreen->width, pScreen->height,
-                                          vncFbptr[pScreen->myNum],
-                                          vncFbstride[pScreen->myNum]);
+  return TRUE;
+}
 
-  vncHooksScreen->desktop->unblockUpdates();
+static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
+                                       CARD16 width, CARD16 height,
+                                       CARD32 mmWidth, CARD32 mmHeight)
+{
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+  Bool ret;
+
+  vncPreScreenResize(pScreen);
+
+  rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
+  ret = (*rp->rrScreenSetSize)(pScreen, width, height, mmWidth, mmHeight);
+  rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
+
+  vncPostScreenResize(pScreen, ret);
+
+  if (!ret)
+    return FALSE;
 
-  // Mark entire screen as changed
-  box.x1 = 0;
-  box.y1 = 0;
-  box.x2 = pScreen->width;
-  box.y2 = pScreen->height;
-  REGION_INIT(pScreen, &reg, &box, 1);
+  return TRUE;
+}
+
+static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
+                                 RRModePtr mode, int x, int y,
+                                 Rotation rotation, int num_outputs,
+                                 RROutputPtr *outputs)
+{
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+  Bool ret;
+
+  rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
+  ret = (*rp->rrCrtcSet)(pScreen, crtc, mode, x, y, rotation,
+                         num_outputs, outputs);
+  rp->rrCrtcSet = vncHooksRandRCrtcSet;
+
+  if (!ret)
+    return FALSE;
 
-  vncHooksScreen->desktop->add_changed(&reg);
+  vncHooksScreen->desktop->refreshScreenLayout();
 
   return TRUE;
 }
index 08ebfbe362184fcf9d8430e5d9553f1c7becb2df..b5fbe46923d9f24102428814818530a74bf6f4f7 100644 (file)
@@ -25,6 +25,8 @@
 #include <rfb/Configuration.h>
 #include <rfb/Logger_stdio.h>
 #include <rfb/LogWriter.h>
+#include <rfb/ScreenSet.h>
+#include <rfb/screenTypes.h>
 
 extern "C" {
 #define class c_class
@@ -98,3 +100,10 @@ static void vncExtensionInitWithParams(INITARGS)
   vncExtensionInit();
 }
 }
+
+unsigned int vncSetScreenLayout(ScreenPtr pScreen,
+                                int fb_width, int fb_height,
+                                const rfb::ScreenSet& layout)
+{
+    return rfb::resultProhibited;
+}
index 8d0df90cc5f89dd4ee5d6c3750e7ff2039fd4880..adc61b214dbbcf9cbdb4feabf7123d728e342bcb 100644 (file)
@@ -859,45 +859,8 @@ static miPointerScreenFuncRec vfbPointerCursorFuncs = {
 
 static Bool vncRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
 {
-  Bool ret, gotCurrent = FALSE;
-  int i;
-
-  const int widths[] =  { 1920, 1920, 1600, 1680, 1400, 1360, 1280, 1280, 1280, 1280, 1024, 800, 640 };
-  const int heights[] = { 1200, 1080, 1200, 1050, 1050,  768, 1024,  960,  800,  720,  768, 600, 480 };
-
-  for (i = 0;i < sizeof(widths)/sizeof(*widths);i++) {
-    RRScreenSizePtr pSize;
-
-    pSize = RRRegisterSize(pScreen, widths[i], heights[i],
-                           pScreen->mmWidth, pScreen->mmHeight);
-    if (!pSize)
-      return FALSE;
-
-    ret = RRRegisterRate(pScreen, pSize, 60);
-    if (!ret)
-      return FALSE;
-
-    if ((widths[i] == pScreen->width) && (heights[i] == pScreen->height)) {
-      RRSetCurrentConfig(pScreen, RR_Rotate_0, 60, pSize);
-      gotCurrent = TRUE;
-    }
-  }
-
-  if (!gotCurrent) {
-    RRScreenSizePtr pSize;
-
-    pSize = RRRegisterSize(pScreen, pScreen->width, pScreen->height,
-                           pScreen->mmWidth, pScreen->mmHeight);
-    if (!pSize)
-      return FALSE;
-
-    RRRegisterRate(pScreen, pSize, 60);
-
-    RRSetCurrentConfig(pScreen, RR_Rotate_0, 60, pSize);
-  }
-
-  *rotations = RR_Rotate_0;
-
+  // We update all information right away, so there is nothing to
+  // do here.
   return TRUE;
 }
 
@@ -1050,16 +1013,19 @@ xf86SetRootClip (ScreenPtr pScreen, Bool enable)
     FlushAllOutput ();
 }
 
-static Bool vncRandRSetConfig (ScreenPtr pScreen, Rotation rotation,
-                   int rate, RRScreenSizePtr pSize)
+static RRModePtr vncRandRModeGet(int width, int height);
+
+static Bool vncRandRScreenSetSize(ScreenPtr pScreen,
+                                  CARD16 width, CARD16 height,
+                                  CARD32 mmWidth, CARD32 mmHeight)
 {
     vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
     vfbFramebufferInfo fb;
+    rrScrPrivPtr rp = rrGetScrPriv(pScreen);
     PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
     void *pbits;
     Bool ret;
     int oldwidth, oldheight, oldmmWidth, oldmmHeight;
-    int dpix, dpiy;
 
     /* Prevent updates while we fiddle */
     xf86SetRootClip(pScreen, FALSE);
@@ -1070,17 +1036,11 @@ static Bool vncRandRSetConfig (ScreenPtr pScreen, Rotation rotation,
     oldmmWidth = pScreen->mmWidth;
     oldmmHeight = pScreen->mmHeight;
 
-    /* Compute the current DPI (for use later) */
-    dpix = (pScreen->width * 254 + pScreen->mmWidth * 5) / (pScreen->mmWidth * 10);
-    dpiy = (pScreen->height * 254 + pScreen->mmHeight * 5) / (pScreen->mmHeight * 10);
-
     /* Then set the new dimensions */
-    pScreen->width = pSize->width;
-    pScreen->height = pSize->height;
-
-    /* Try to keep the same DPI as we do not have a physical screen */
-    pScreen->mmWidth = (pScreen->width * 254 + dpix * 5) / (dpix * 10);
-    pScreen->mmHeight = (pScreen->height * 254 + dpiy * 5) / (dpiy * 10);
+    pScreen->width = width;
+    pScreen->height = height;
+    pScreen->mmWidth = mmWidth;
+    pScreen->mmHeight = mmHeight;
 
     /* Allocate a new framebuffer */
     memset(&fb, 0, sizeof(vfbFramebufferInfo));
@@ -1130,9 +1090,164 @@ static Bool vncRandRSetConfig (ScreenPtr pScreen, Rotation rotation,
     /* Restore ability to update screen, now with new dimensions */
     xf86SetRootClip(pScreen, TRUE);
 
+    /*
+     * Let RandR know we changed something (it doesn't assume that
+     * TRUE means something changed for some reason...).
+     */
+    RRScreenSizeNotify(pScreen);
+
+    /* Crop all CRTCs to the new screen */
+    for (int i = 0;i < rp->numCrtcs;i++) {
+        RRCrtcPtr crtc;
+        RRModePtr mode;
+
+        crtc = rp->crtcs[i];
+
+        /* Disabled? */
+        if (crtc->mode == NULL)
+            continue;
+
+        /* Fully inside? */
+        if ((crtc->x + crtc->mode->mode.width <= width) &&
+            (crtc->y + crtc->mode->mode.height <= height))
+            continue;
+
+        /* Fully outside? */
+        if ((crtc->x >= width) || (crtc->y >= height)) {
+            /* Disable it */
+            ret = RRCrtcNotify(crtc, NULL, crtc->x, crtc->y, crtc->rotation,
+                               crtc->numOutputs, crtc->outputs);
+            if (!ret)
+                ErrorF("Warning: Unable to disable CRTC that is outside of new screen dimensions");
+            continue;
+        }
+
+        /* Just needs to be resized */
+        mode = vncRandRModeGet(width - crtc->x, height - crtc->y);
+        if (mode == NULL) {
+            ErrorF("Warning: Unable to create custom mode for %dx%d",
+                   width - crtc->x, height - crtc->y);
+            continue;
+        }
+
+        ret = RRCrtcNotify(crtc, mode, crtc->x, crtc->y, crtc->rotation,
+                           crtc->numOutputs, crtc->outputs);
+        RRModeDestroy(mode);
+        if (!ret)
+            ErrorF("Warning: Unable to crop CRTC to new screen dimensions");
+    }
+
+    return TRUE;
+}
+
+static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
+                            int x, int y, Rotation rotation, int num_outputs,
+                            RROutputPtr *outputs)
+{
+    Bool ret;
+
+    /* Let RandR know we approve, and let it update its internal state */
+    ret = RRCrtcNotify(crtc, mode, x, y, rotation, num_outputs, outputs);
+    if (!ret)
+        return FALSE;
+
+    return TRUE;
+}
+
+static Bool vncRandROutputValidateMode(ScreenPtr pScreen,
+                                       RROutputPtr output, RRModePtr mode)
+{
+    /* We have no hardware so any mode works */
     return TRUE;
 }
 
+static void vncRandRModeDestroy(ScreenPtr pScreen, RRModePtr mode)
+{
+    /* We haven't allocated anything so nothing to destroy */
+}
+
+static const char vncRandROutputName[] = "VNC";
+
+static const int vncRandRWidths[] =  { 1920, 1920, 1600, 1680, 1400, 1360, 1280, 1280, 1280, 1280, 1024, 800, 640 };
+static const int vncRandRHeights[] = { 1200, 1080, 1200, 1050, 1050,  768, 1024,  960,  800,  720,  768, 600, 480 };
+
+static RRModePtr vncRandRModeGet(int width, int height)
+{
+    xRRModeInfo        modeInfo;
+    char name[100];
+    RRModePtr mode;
+
+    memset(&modeInfo, 0, sizeof(modeInfo));
+    sprintf(name, "%dx%d", width, height);
+    
+    modeInfo.width = width;
+    modeInfo.height = height;
+    modeInfo.hTotal = width;
+    modeInfo.vTotal = height;
+    modeInfo.dotClock = ((CARD32)width * (CARD32)height * 60);
+    modeInfo.nameLength = strlen(name);
+    mode = RRModeGet(&modeInfo, name);
+    if (mode == NULL)
+        return NULL;
+
+    return mode;
+}
+
+static Bool vncRandRInit(ScreenPtr pScreen)
+{
+    RRCrtcPtr crtc;
+    RROutputPtr output;
+    RRModePtr mode;
+
+    if (!RRInit())
+        return FALSE;
+
+    /* These are completely arbitrary */
+    RRScreenSetSizeRange(pScreen, 32, 32, 32768, 32768);
+
+    /* Start with a single CRTC with a single output */
+    crtc = RRCrtcCreate(pScreen, 0 /* id */);
+
+    /* We don't actually support gamma, but xrandr complains when it is missing */
+    RRCrtcGammaSetSize (crtc, 256);
+
+    output = RROutputCreate(pScreen, vncRandROutputName,
+                            sizeof(vncRandROutputName), NULL);
+    RROutputSetCrtcs(output, &crtc, 1);
+    RROutputSetConnection(output, RR_Connected);
+
+    /* Populate a list of default modes */
+    RRModePtr modes[sizeof(vncRandRWidths)/sizeof(*vncRandRWidths)];
+    int num_modes;
+
+    num_modes = 0;
+    for (int i = 0;i < sizeof(vncRandRWidths)/sizeof(*vncRandRWidths);i++) {
+        mode = vncRandRModeGet(vncRandRWidths[i], vncRandRHeights[i]);
+        if (mode != NULL) {
+            modes[num_modes] = mode;
+            num_modes++;
+        }
+    }
+
+    RROutputSetModes(output, modes, num_modes, 0);
+
+    /* Make sure the current screen size is the active mode */
+    mode = vncRandRModeGet(pScreen->width, pScreen->height);
+    if (mode == NULL)
+        return FALSE;
+
+    RRCrtcNotify(crtc, mode, 0, 0, RR_Rotate_0, 1, &output);
+
+    return TRUE;
+}
+
+unsigned int vncSetScreenLayout(ScreenPtr pScreen,
+                                int fb_width, int fb_height,
+                                const rfb::ScreenSet& layout)
+{
+    return rfb::resultProhibited;
+}
+
 #endif
 
 static Bool
@@ -1291,8 +1406,16 @@ vfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv)
     if (!ret) return FALSE;
 
     rp = rrGetScrPriv(pScreen);
+
     rp->rrGetInfo = vncRandRGetInfo;
-    rp->rrSetConfig = vncRandRSetConfig;
+    rp->rrSetConfig = NULL;
+    rp->rrScreenSetSize = vncRandRScreenSetSize;
+    rp->rrCrtcSet = vncRandRCrtcSet;
+    rp->rrOutputValidateMode = vncRandROutputValidateMode;
+    rp->rrModeDestroy = vncRandRModeDestroy;
+
+    ret = vncRandRInit(pScreen);
+    if (!ret) return FALSE;
 #endif