Index: trunk/src/VBox/Main/ConsoleVRDPServer.cpp
===================================================================
--- trunk/src/VBox/Main/ConsoleVRDPServer.cpp	(revision 3127)
+++ trunk/src/VBox/Main/ConsoleVRDPServer.cpp	(revision 3153)
@@ -41,5 +41,5 @@
 void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSetCallback)     (HVRDPSERVER hServer, VRDPSERVERCALLBACK *pcallback, void *pvUser);
 void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPShutdownServer)  (HVRDPSERVER hServer);
-void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUpdateBitmap)(HVRDPSERVER hServer, unsigned x, unsigned y, unsigned w, unsigned h);
+void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUpdateBitmap)(HVRDPSERVER hServer, unsigned uScreenId, unsigned x, unsigned y, unsigned w, unsigned h);
 void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendResize)      (HVRDPSERVER hServer);
 void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendAudioSamples)(HVRDPSERVER hserver, void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format);
@@ -50,5 +50,5 @@
 void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUSBRequest)  (HVRDPSERVER hserver, void *pvParms, uint32_t cbParms);
 #endif /* VRDP_MC */
-void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUpdate)      (HVRDPSERVER hServer, void *pvUpdate, uint32_t cbUpdate);
+void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUpdate)      (HVRDPSERVER hServer, unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate);
 void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPQueryInfo)       (HVRDPSERVER hserver, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut);
 void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPClipboard)       (HVRDPSERVER hserver, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData, uint32_t *pcbActualRead);
@@ -125,4 +125,5 @@
         if (VBOX_SUCCESS(rc))
         {
+#ifndef VRDP_MC
             LogFlow(("VRDP server created: %p, will set mFramebuffer\n", mhServer));
 
@@ -133,5 +134,5 @@
 
             LogFlow(("Framebuffer %p set for the VRDP server\n", framebuffer));
-            
+#endif /* !VRDP_MC */
 #ifdef VBOX_WITH_USB
 #ifdef VRDP_MC
@@ -923,9 +924,9 @@
 
 
-void ConsoleVRDPServer::SendUpdate (void *pvUpdate, uint32_t cbUpdate) const
+void ConsoleVRDPServer::SendUpdate (unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
 {
 #ifdef VBOX_VRDP
     if (mpfnVRDPSendUpdate)
-        mpfnVRDPSendUpdate (mhServer, pvUpdate, cbUpdate);
+        mpfnVRDPSendUpdate (mhServer, uScreenId, pvUpdate, cbUpdate);
 #endif
 }
@@ -939,9 +940,9 @@
 }
 
-void ConsoleVRDPServer::SendUpdateBitmap (uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
+void ConsoleVRDPServer::SendUpdateBitmap (unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
 {
 #ifdef VBOX_VRDP
     if (mpfnVRDPSendUpdateBitmap)
-        mpfnVRDPSendUpdateBitmap (mhServer, x, y, w, h);
+        mpfnVRDPSendUpdateBitmap (mhServer, uScreenId, x, y, w, h);
 #endif
 }
@@ -1022,5 +1023,7 @@
             {
                 DEFSYMENTRY(VRDPStartServer),
+#ifndef VRDP_MC
                 DEFSYMENTRY(VRDPSetFramebuffer),
+#endif /* VRDP_MC */
                 DEFSYMENTRY(VRDPSetCallback),
                 DEFSYMENTRY(VRDPShutdownServer),
Index: trunk/src/VBox/Main/DisplayImpl.cpp
===================================================================
--- trunk/src/VBox/Main/DisplayImpl.cpp	(revision 3127)
+++ trunk/src/VBox/Main/DisplayImpl.cpp	(revision 3153)
@@ -91,5 +91,5 @@
     mLastHeight = 0;
 
-    mu32ResizeStatus = ResizeStatus_Void;
+//    mu32ResizeStatus = ResizeStatus_Void;
 
     return S_OK;
@@ -128,9 +128,36 @@
     // by default, we have an internal framebuffer which is
     // NULL, i.e. a black hole for no display output
-    mFramebuffer = 0;
+//    mFramebuffer = 0;
     mInternalFramebuffer = true;
     mFramebufferOpened = false;
     mSupportedAccelOps = 0;
 
+    ULONG ul;
+    mParent->machine()->COMGETTER(MonitorCount)(&ul);
+    mcMonitors = ul;
+
+    for (ul = 0; ul < mcMonitors; ul++)
+    {
+        maFramebuffers[ul].u32Offset = 0;
+        maFramebuffers[ul].u32MaxFramebufferSize = 0;
+        maFramebuffers[ul].u32InformationSize = 0;
+
+        maFramebuffers[ul].pFramebuffer = NULL;
+
+        maFramebuffers[ul].xOrigin = 0;
+        maFramebuffers[ul].yOrigin = 0;
+
+        maFramebuffers[ul].w = 0;
+        maFramebuffers[ul].h = 0;
+
+        maFramebuffers[ul].pHostEvents = NULL;
+
+        maFramebuffers[ul].u32ResizeStatus = ResizeStatus_Void;
+
+        maFramebuffers[ul].fDefaultFormat = false;
+
+        memset (&maFramebuffers[ul].dirtyRect, 0 , sizeof (maFramebuffers[ul].dirtyRect));
+    }
+
     mParent->RegisterCallback(this);
 
@@ -150,5 +177,11 @@
     AssertReturn (isReady(), (void) 0);
 
-    mFramebuffer.setNull();
+//    mFramebuffer.setNull();
+    ULONG ul;
+    for (ul = 0; ul < mcMonitors; ul++)
+    {
+        maFramebuffers[ul].pFramebuffer = NULL;
+    }
+
     RTSemEventMultiDestroy(mUpdateSem);
 
@@ -189,5 +222,5 @@
  *  @thread EMT
  */
-static int callFramebufferResize (IFramebuffer *pFramebuffer, FramebufferPixelFormat_T pixelFormat, void *pvVRAM, uint32_t cbLine, int w, int h)
+static int callFramebufferResize (IFramebuffer *pFramebuffer, unsigned uScreenId, FramebufferPixelFormat_T pixelFormat, void *pvVRAM, uint32_t cbLine, int w, int h)
 {
     Assert (pFramebuffer);
@@ -196,5 +229,5 @@
     BOOL finished = TRUE;
 
-    pFramebuffer->RequestResize (pixelFormat, (BYTE *) pvVRAM, cbLine, w, h, &finished);
+    pFramebuffer->RequestResize (uScreenId, pixelFormat, (BYTE *) pvVRAM, cbLine, w, h, &finished);
 
     if (!finished)
@@ -219,11 +252,12 @@
  *  @thread EMT
  */
-int Display::handleDisplayResize (uint32_t bpp, void *pvVRAM, uint32_t cbLine, int w, int h)
-{
-    LogRel (("Display::handleDisplayResize(): pvVRAM=%p w=%d h=%d bpp=%d cbLine=0x%X\n",
-             pvVRAM, w, h, bpp, cbLine));
+int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM, uint32_t cbLine, int w, int h)
+{
+    LogRel (("Display::handleDisplayResize(): uScreenId = %d, pvVRAM=%p w=%d h=%d bpp=%d cbLine=0x%X\n",
+             uScreenId, pvVRAM, w, h, bpp, cbLine));
 
     /* If there is no framebuffer, this call is not interesting. */
-    if (mFramebuffer.isNull())
+    if (   uScreenId >= mcMonitors
+        || maFramebuffers[uScreenId].pFramebuffer.isNull())
     {
         return VINF_SUCCESS;
@@ -249,5 +283,5 @@
      * disable access to the VGA device by the EMT thread.
      */
-    bool f = ASMAtomicCmpXchgU32 (&mu32ResizeStatus, ResizeStatus_InProgress, ResizeStatus_Void);
+    bool f = ASMAtomicCmpXchgU32 (&maFramebuffers[uScreenId].u32ResizeStatus, ResizeStatus_InProgress, ResizeStatus_Void);
     AssertReleaseMsg(f, ("f = %d\n", f));NOREF(f);
 
@@ -255,7 +289,7 @@
      * The lock is kept, because the framebuffer is in undefined state.
      */
-    mFramebuffer->Lock();
-
-    int rc = callFramebufferResize (mFramebuffer, pixelFormat, pvVRAM, cbLine, w, h);
+    maFramebuffers[uScreenId].pFramebuffer->Lock();
+
+    int rc = callFramebufferResize (maFramebuffers[uScreenId].pFramebuffer, uScreenId, pixelFormat, pvVRAM, cbLine, w, h);
     if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
     {
@@ -269,5 +303,5 @@
 
     /* Set the status so the 'handleResizeCompleted' would work.  */
-    f = ASMAtomicCmpXchgU32 (&mu32ResizeStatus, ResizeStatus_UpdateDisplayData, ResizeStatus_InProgress);
+    f = ASMAtomicCmpXchgU32 (&maFramebuffers[uScreenId].u32ResizeStatus, ResizeStatus_UpdateDisplayData, ResizeStatus_InProgress);
     AssertRelease(f);NOREF(f);
 
@@ -287,41 +321,54 @@
 {
     LogFlowFunc(("\n"));
-    if (!mFramebuffer.isNull())
-    {
-        /* Framebuffer has completed the resize. Update the connector data. */
-        updateDisplayData();
     
-        /* Check the framebuffer pixel format to setup the rendering in VGA device. */
-        FramebufferPixelFormat_T newPixelFormat;
-
-        mFramebuffer->COMGETTER(PixelFormat) (&newPixelFormat);
-
-        mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, newPixelFormat == FramebufferPixelFormat_PixelFormatDefault);
-    }
+    unsigned uScreenId;
+    for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
+    {
+        DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
+
+        /* Try to into non resizing state. */
+        bool f = ASMAtomicCmpXchgU32 (&pFBInfo->u32ResizeStatus, ResizeStatus_Void, ResizeStatus_UpdateDisplayData);
+
+        if (f == false)
+        {
+            /* This is not the display that has completed resizing. */
+            continue;
+        }
+
+        if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && !pFBInfo->pFramebuffer.isNull())
+        {
+            /* Primary framebuffer has completed the resize. Update the connector data for VGA device. */
+            updateDisplayData();
+    
+            /* Check the framebuffer pixel format to setup the rendering in VGA device. */
+            FramebufferPixelFormat_T newPixelFormat;
+            pFBInfo->pFramebuffer->COMGETTER(PixelFormat) (&newPixelFormat);
+
+            pFBInfo->fDefaultFormat = (newPixelFormat == FramebufferPixelFormat_PixelFormatDefault);
+
+            mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, pFBInfo->fDefaultFormat);
+        }
 
 #ifdef DEBUG_sunlover
-    if (!stam)
-    {
-        /* protect mpVM */
-        Console::SafeVMPtr pVM (mParent);
-        AssertComRC (pVM.rc());
-
-        STAM_REG(pVM, &StatDisplayRefresh, STAMTYPE_PROFILE, "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates.");
-        stam = 1;
-    }
+        if (!stam)
+        {
+            /* protect mpVM */
+            Console::SafeVMPtr pVM (mParent);
+            AssertComRC (pVM.rc());
+
+            STAM_REG(pVM, &StatDisplayRefresh, STAMTYPE_PROFILE, "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates.");
+            stam = 1;
+        }
 #endif /* DEBUG_sunlover */
 
-    /* Inform VRDP server about the change of display parameters. */
-    LogFlowFunc (("Calling VRDP\n"));
-    mParent->consoleVRDPServer()->SendResize();
-
-    /* Go into non resizing state. */
-    bool f = ASMAtomicCmpXchgU32 (&mu32ResizeStatus, ResizeStatus_Void, ResizeStatus_UpdateDisplayData);
-    AssertRelease(f);NOREF(f);
-    
-    if (!mFramebuffer.isNull())
-    {
-        /* Unlock framebuffer after evrything is done. */
-        mFramebuffer->Unlock();
+        /* Inform VRDP server about the change of display parameters. */
+        LogFlowFunc (("Calling VRDP\n"));
+        mParent->consoleVRDPServer()->SendResize();
+
+        if (!pFBInfo->pFramebuffer.isNull())
+        {
+            /* Unlock framebuffer after evrything is done. */
+            pFBInfo->pFramebuffer->Unlock();
+        }
     }
 }
@@ -359,4 +406,32 @@
     }
 }
+
+unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int *py, int *pw, int *ph)
+{
+    DISPLAYFBINFO *pInfo = pInfos;
+    unsigned uScreenId;
+    Log(("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph));
+    for (uScreenId = 0; uScreenId < cInfos; uScreenId++, pInfo++)
+    {
+        Log(("    [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h));
+        if (   (pInfo->xOrigin <= *px && *px < pInfo->xOrigin + (int)pInfo->w)
+            && (pInfo->yOrigin <= *py && *py < pInfo->yOrigin + (int)pInfo->h))
+        {
+            /* The rectangle belongs to the screen. Correct coordinates. */
+            *px -= pInfo->xOrigin;
+            *py -= pInfo->yOrigin;
+            Log(("    -> %d,%d", *px, *py));
+            break;
+        }
+    }
+    if (uScreenId == cInfos)
+    {
+        /* Map to primary screen. */
+        uScreenId = 0;
+    }
+    Log((" scr %d\n", uScreenId));
+    return uScreenId;
+}
+
 
 /**
@@ -372,10 +447,4 @@
 void Display::handleDisplayUpdate (int x, int y, int w, int h)
 {
-    // if there is no framebuffer, this call is not interesting
-    if (mFramebuffer.isNull())
-        return;
-
-    mFramebuffer->Lock();
-
 #ifdef DEBUG_sunlover
     LogFlowFunc (("%d,%d %dx%d (%d,%d)\n",
@@ -383,5 +452,9 @@
 #endif /* DEBUG_sunlover */
 
+#ifdef VRDP_MC
+    unsigned uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);
+#else
     checkCoordBounds (&x, &y, &w, &h, mpDrv->Connector.cx, mpDrv->Connector.cy);
+#endif /* VRDP_MC */
 
 #ifdef DEBUG_sunlover
@@ -389,8 +462,16 @@
 #endif /* DEBUG_sunlover */
 
+    IFramebuffer *pFramebuffer = maFramebuffers[uScreenId].pFramebuffer;
+
+    // if there is no framebuffer, this call is not interesting
+    if (pFramebuffer == NULL)
+        return;
+
+    pFramebuffer->Lock();
+
     /* special processing for the internal framebuffer */
     if (mInternalFramebuffer)
     {
-        mFramebuffer->Unlock();
+        pFramebuffer->Unlock();
     } else
     {
@@ -400,5 +481,5 @@
         RTSemEventMultiReset(mUpdateSem);
 
-        mFramebuffer->NotifyUpdate(x, y, w, h, &finished);
+        pFramebuffer->NotifyUpdate(x, y, w, h, &finished);
 
         if (!finished)
@@ -408,9 +489,9 @@
              *  the event so we have to halt the VM until it's done
              */
-            mFramebuffer->Unlock();
+            pFramebuffer->Unlock();
             RTSemEventMultiWait(mUpdateSem, RT_INDEFINITE_WAIT);
         } else
         {
-            mFramebuffer->Unlock();
+            pFramebuffer->Unlock();
         }
 
@@ -420,5 +501,5 @@
              * Inform the server here only if VBVA is disabled.
              */
-            mParent->consoleVRDPServer()->SendUpdateBitmap(x, y, w, h);
+            mParent->consoleVRDPServer()->SendUpdateBitmap(uScreenId, x, y, w, h);
         }
     }
@@ -429,38 +510,28 @@
 {
     /* Copies of object's pointers used by vbvaRgn functions. */
-    IFramebuffer     *pFramebuffer;
+    DISPLAYFBINFO    *paFramebuffers;
+    unsigned          cMonitors;
     Display          *pDisplay;
     PPDMIDISPLAYPORT  pPort;
 
-    /* The Framebuffer has default format and must be updates immediately. */
-    bool fDefaultFormat;
-
-    /* Merged rectangles. */
-    int32_t xLeft;
-    int32_t xRight;
-    int32_t yTop;
-    int32_t yBottom;
-
 } VBVADIRTYREGION;
 
-static void vbvaRgnInit (VBVADIRTYREGION *prgn, IFramebuffer *pfb, Display *pd, PPDMIDISPLAYPORT pp)
-{
-    memset (prgn, 0, sizeof (VBVADIRTYREGION));
-
-    prgn->pFramebuffer = pfb;
+static void vbvaRgnInit (VBVADIRTYREGION *prgn, DISPLAYFBINFO *paFramebuffers, unsigned cMonitors, Display *pd, PPDMIDISPLAYPORT pp)
+{
+    prgn->paFramebuffers = paFramebuffers;
+    prgn->cMonitors = cMonitors;
     prgn->pDisplay = pd;
     prgn->pPort = pp;
-
-    if (pfb)
-    {
-        FramebufferPixelFormat_T pixelFormat;
-        pfb->COMGETTER(PixelFormat) (&pixelFormat);
-        prgn->fDefaultFormat = (pixelFormat == FramebufferPixelFormat_PixelFormatDefault);
-    }
-
-    return;
-}
-
-static void vbvaRgnDirtyRect (VBVADIRTYREGION *prgn, VBVACMDHDR *phdr)
+    
+    unsigned uScreenId;
+    for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)
+    {
+        DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
+
+        memset (&pFBInfo->dirtyRect, 0, sizeof (pFBInfo->dirtyRect));
+    }
+}
+
+static void vbvaRgnDirtyRect (VBVADIRTYREGION *prgn, unsigned uScreenId, VBVACMDHDR *phdr)
 {
     LogFlowFunc (("x = %d, y = %d, w = %d, h = %d\n",
@@ -483,38 +554,41 @@
     int32_t yBottom = phdr->y + phdr->h;
 
-    if (prgn->xRight == 0)
+    DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
+
+    if (pFBInfo->dirtyRect.xRight == 0)
     {
         /* This is the first rectangle to be added. */
-        prgn->xLeft   = phdr->x;
-        prgn->yTop    = phdr->y;
-        prgn->xRight  = xRight;
-        prgn->yBottom = yBottom;
+        pFBInfo->dirtyRect.xLeft   = phdr->x;
+        pFBInfo->dirtyRect.yTop    = phdr->y;
+        pFBInfo->dirtyRect.xRight  = xRight;
+        pFBInfo->dirtyRect.yBottom = yBottom;
     }
     else
     {
         /* Adjust region coordinates. */
-        if (prgn->xLeft > phdr->x)
-        {
-            prgn->xLeft = phdr->x;
-        }
-
-        if (prgn->yTop > phdr->y)
-        {
-            prgn->yTop = phdr->y;
-        }
-
-        if (prgn->xRight < xRight)
-        {
-            prgn->xRight = xRight;
-        }
-
-        if (prgn->yBottom < yBottom)
-        {
-            prgn->yBottom = yBottom;
-        }
-    }
-
-    if (prgn->fDefaultFormat)
-    {
+        if (pFBInfo->dirtyRect.xLeft > phdr->x)
+        {
+            pFBInfo->dirtyRect.xLeft = phdr->x;
+        }
+
+        if (pFBInfo->dirtyRect.yTop > phdr->y)
+        {
+            pFBInfo->dirtyRect.yTop = phdr->y;
+        }
+
+        if (pFBInfo->dirtyRect.xRight < xRight)
+        {
+            pFBInfo->dirtyRect.xRight = xRight;
+        }
+
+        if (pFBInfo->dirtyRect.yBottom < yBottom)
+        {
+            pFBInfo->dirtyRect.yBottom = yBottom;
+        }
+    }
+
+    if (pFBInfo->fDefaultFormat)
+    {
+        //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
         prgn->pPort->pfnUpdateDisplayRect (prgn->pPort, phdr->x, phdr->y, phdr->w, phdr->h);
         prgn->pDisplay->handleDisplayUpdate (phdr->x, phdr->y, phdr->w, phdr->h);
@@ -524,13 +598,16 @@
 }
 
-static void vbvaRgnUpdateFramebuffer (VBVADIRTYREGION *prgn)
-{
-    uint32_t w = prgn->xRight - prgn->xLeft;
-    uint32_t h = prgn->yBottom - prgn->yTop;
-
-    if (!prgn->fDefaultFormat && prgn->pFramebuffer && w != 0 && h != 0)
-    {
-        prgn->pPort->pfnUpdateDisplayRect (prgn->pPort, prgn->xLeft, prgn->yTop, w, h);
-        prgn->pDisplay->handleDisplayUpdate (prgn->xLeft, prgn->yTop, w, h);
+static void vbvaRgnUpdateFramebuffer (VBVADIRTYREGION *prgn, unsigned uScreenId)
+{
+    DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
+
+    uint32_t w = pFBInfo->dirtyRect.xRight - pFBInfo->dirtyRect.xLeft;
+    uint32_t h = pFBInfo->dirtyRect.yBottom - pFBInfo->dirtyRect.yTop;
+
+    if (!pFBInfo->fDefaultFormat && pFBInfo->pFramebuffer && w != 0 && h != 0)
+    {
+        //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
+        prgn->pPort->pfnUpdateDisplayRect (prgn->pPort, pFBInfo->dirtyRect.xLeft, pFBInfo->dirtyRect.yTop, w, h);
+        prgn->pDisplay->handleDisplayUpdate (pFBInfo->dirtyRect.xLeft, pFBInfo->dirtyRect.yTop, w, h);
     }
 }
@@ -539,5 +616,7 @@
                                 bool fVideoAccelEnabled,
                                 bool fVideoAccelVRDP,
-                                uint32_t fu32SupportedOrders)
+                                uint32_t fu32SupportedOrders,
+                                DISPLAYFBINFO *paFBInfos,
+                                unsigned cFBInfos)
 {
     if (pVbvaMemory)
@@ -559,4 +638,13 @@
 
         pVbvaMemory->fu32ModeFlags = fu32Flags;
+    }
+
+    unsigned uScreenId;
+    for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)
+    {
+        if (paFBInfos[uScreenId].pHostEvents)
+        {
+            paFBInfos[uScreenId].pHostEvents->fu32Events |= VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;
+        }
     }
 }
@@ -636,5 +724,5 @@
 
     /* Update entire display. */
-    if (mu32ResizeStatus == ResizeStatus_Void)
+    if (maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].u32ResizeStatus == ResizeStatus_Void)
     {
         mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort);
@@ -659,5 +747,5 @@
 
         /* Initialize the hardware memory. */
-        vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
+        vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
         mpVbvaMemory->off32Data = 0;
         mpVbvaMemory->off32Free = 0;
@@ -706,5 +794,5 @@
         mfu32SupportedOrders = 0;
         
-        vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
+        vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
         
         LogRel(("VBVA: VRDP acceleration has been disabled.\n"));
@@ -721,5 +809,5 @@
         mfu32SupportedOrders = ~0;
         
-        vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
+        vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
     
         LogRel(("VBVA: VRDP acceleration has been requested.\n"));
@@ -749,5 +837,5 @@
     }
 
-    vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
+    vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
 
     LogRel(("VBVA: VRDP acceleration has been %s.\n", fEnable? "requested": "disabled"));
@@ -1054,15 +1142,16 @@
 
     /* Process the ring buffer */
-
-    bool fFramebufferIsNull = mFramebuffer.isNull();
-
-    if (!fFramebufferIsNull)
-    {
-        mFramebuffer->Lock();
+    unsigned uScreenId;
+    for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
+    {
+        if (!maFramebuffers[uScreenId].pFramebuffer.isNull())
+        {
+            maFramebuffers[uScreenId].pFramebuffer->Lock ();
+        }
     }
 
     /* Initialize dirty rectangles accumulator. */
     VBVADIRTYREGION rgn;
-    vbvaRgnInit (&rgn, mFramebuffer, this, mpDrv->pUpPort);
+    vbvaRgnInit (&rgn, maFramebuffers, mcMonitors, this, mpDrv->pUpPort);
 
     for (;;)
@@ -1089,5 +1178,5 @@
         }
 
-        if (cbCmd != 0 && !fFramebufferIsNull)
+        if (cbCmd != 0)
         {
 #ifdef DEBUG_sunlover
@@ -1096,5 +1185,21 @@
 #endif /* DEBUG_sunlover */
 
-            if (mu32ResizeStatus == ResizeStatus_Void)
+            VBVACMDHDR hdrSaved = *phdr;
+
+            int x = phdr->x;
+            int y = phdr->y;
+            int w = phdr->w;
+            int h = phdr->h;
+
+            uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);
+
+            phdr->x = (int16_t)x;
+            phdr->y = (int16_t)y;
+            phdr->w = (uint16_t)w;
+            phdr->h = (uint16_t)h;
+            
+            DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
+
+            if (pFBInfo->u32ResizeStatus == ResizeStatus_Void)
             {
                 /* Handle the command.
@@ -1111,8 +1216,10 @@
 
                 /* Accumulate the update. */
-                vbvaRgnDirtyRect (&rgn, phdr);
+                vbvaRgnDirtyRect (&rgn, uScreenId, phdr);
 
                 /* Forward the command to VRDP server. */
-                mParent->consoleVRDPServer()->SendUpdate (phdr, cbCmd);
+                mParent->consoleVRDPServer()->SendUpdate (uScreenId, phdr, cbCmd);
+                
+                *phdr = hdrSaved;
             }
         }
@@ -1121,13 +1228,16 @@
     }
 
-    if (!fFramebufferIsNull)
-    {
-        mFramebuffer->Unlock ();
-    }
-
-    if (mu32ResizeStatus == ResizeStatus_Void)
-    {
-        /* Draw the framebuffer. */
-        vbvaRgnUpdateFramebuffer (&rgn);
+    for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
+    {
+        if (!maFramebuffers[uScreenId].pFramebuffer.isNull())
+        {
+            maFramebuffers[uScreenId].pFramebuffer->Unlock ();
+        }
+
+        if (maFramebuffers[uScreenId].u32ResizeStatus == ResizeStatus_Void)
+        {
+            /* Draw the framebuffer. */
+            vbvaRgnUpdateFramebuffer (&rgn, uScreenId);
+        }
     }
 }
@@ -1235,5 +1345,5 @@
                                (PFNRT) changeFramebuffer, 3,
                                this, static_cast <IFramebuffer *> (frameBuf),
-                               true /* aInternal */);
+                               true /* aInternal */, VBOX_VIDEO_PRIMARY_SCREEN);
         if (VBOX_SUCCESS (vrc))
             vrc = pReq->iStatus;
@@ -1247,5 +1357,5 @@
     {
         /* No VM is created (VM is powered off), do a direct call */
-        int vrc = changeFramebuffer (this, frameBuf, true /* aInternal */);
+        int vrc = changeFramebuffer (this, frameBuf, true /* aInternal */, VBOX_VIDEO_PRIMARY_SCREEN);
         ComAssertRCRet (vrc, E_FAIL);
     }
@@ -1263,9 +1373,9 @@
 
     /* only allowed for internal framebuffers */
-    if (mInternalFramebuffer && !mFramebufferOpened && !mFramebuffer.isNull())
+    if (mInternalFramebuffer && !mFramebufferOpened && !maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer.isNull())
     {
         CHECK_CONSOLE_DRV (mpDrv);
 
-        mFramebuffer->Lock();
+        maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer->Lock();
         mFramebufferOpened = true;
         *address = mpDrv->Connector.pu8Data;
@@ -1286,5 +1396,5 @@
         CHECK_CONSOLE_DRV (mpDrv);
 
-        mFramebuffer->Unlock();
+        maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer->Unlock();
         mFramebufferOpened = false;
         return S_OK;
@@ -1315,5 +1425,5 @@
         int vrc = VMR3ReqCall (pVM, &pReq, RT_INDEFINITE_WAIT,
                                (PFNRT) changeFramebuffer, 3,
-                               this, frameBuf, false /* aInternal */);
+                               this, frameBuf, false /* aInternal */, VBOX_VIDEO_PRIMARY_SCREEN);
         if (VBOX_SUCCESS (vrc))
             vrc = pReq->iStatus;
@@ -1327,7 +1437,70 @@
     {
         /* No VM is created (VM is powered off), do a direct call */
-        int vrc = changeFramebuffer (this, frameBuf, false /* aInternal */);
+        int vrc = changeFramebuffer (this, frameBuf, false /* aInternal */, VBOX_VIDEO_PRIMARY_SCREEN);
         ComAssertRCRet (vrc, E_FAIL);
     }
+
+    return S_OK;
+}
+
+STDMETHODIMP Display::SetFramebuffer (ULONG aScreenId, IFramebuffer * aFramebuffer)
+{
+    LogFlowFunc (("\n"));
+
+    if (!aFramebuffer)
+        return E_POINTER;
+
+    AutoLock lock (this);
+    CHECK_READY();
+
+    Console::SafeVMPtrQuiet pVM (mParent);
+    if (pVM.isOk())
+    {
+        /* Must leave the lock here because the changeFramebuffer will also obtain it. */
+        lock.leave ();
+
+        /* send request to the EMT thread */
+        PVMREQ pReq = NULL;
+        int vrc = VMR3ReqCall (pVM, &pReq, RT_INDEFINITE_WAIT,
+                               (PFNRT) changeFramebuffer, 3,
+                               this, aFramebuffer, false /* aInternal */, aScreenId);
+        if (VBOX_SUCCESS (vrc))
+            vrc = pReq->iStatus;
+        VMR3ReqFree (pReq);
+
+        lock.enter ();
+
+        ComAssertRCRet (vrc, E_FAIL);
+    }
+    else
+    {
+        /* No VM is created (VM is powered off), do a direct call */
+        int vrc = changeFramebuffer (this, aFramebuffer, false /* aInternal */, aScreenId);
+        ComAssertRCRet (vrc, E_FAIL);
+    }
+
+    return S_OK;
+}
+
+STDMETHODIMP Display::QueryFramebuffer (ULONG aScreenId, IFramebuffer * * aFramebuffer, LONG * aXOrigin, LONG * aYOrigin)
+{
+    LogFlowFunc (("aScreenId = %d\n", aScreenId));
+
+    if (!aFramebuffer)
+        return E_POINTER;
+
+    AutoLock lock (this);
+    CHECK_READY();
+
+    /* @todo this should be actually done on EMT. */
+    DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
+
+    *aFramebuffer = pFBInfo->pFramebuffer;
+    if (*aFramebuffer)
+        (*aFramebuffer)->AddRef ();
+    if (aXOrigin)
+        *aXOrigin = pFBInfo->xOrigin;
+    if (aYOrigin)
+        *aYOrigin = pFBInfo->yOrigin;
 
     return S_OK;
@@ -1555,5 +1728,5 @@
  * @returns COM status code
  */
-STDMETHODIMP Display::ResizeCompleted()
+STDMETHODIMP Display::ResizeCompleted(ULONG aScreenId)
 {
     LogFlowFunc (("\n"));
@@ -1576,5 +1749,5 @@
 
     /* Set the flag indicating that the resize has completed and display data need to be updated. */
-    bool f = ASMAtomicCmpXchgU32 (&mu32ResizeStatus, ResizeStatus_UpdateDisplayData, ResizeStatus_InProgress);
+    bool f = ASMAtomicCmpXchgU32 (&maFramebuffers[aScreenId].u32ResizeStatus, ResizeStatus_UpdateDisplayData, ResizeStatus_InProgress);
     AssertRelease(f);NOREF(f);
 
@@ -1608,8 +1781,8 @@
                 "for external framebuffers"));
 
-    mFramebuffer->Lock();
+    maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer->Lock();
     /* signal our semaphore */
     RTSemEventMultiSignal(mUpdateSem);
-    mFramebuffer->Unlock();
+    maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer->Unlock();
 
     return S_OK;
@@ -1647,21 +1820,24 @@
 #endif
 
-    if (mFramebuffer)
+    /* The method is only relevant to the primary framebuffer. */
+    IFramebuffer *pFramebuffer = maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer;
+
+    if (pFramebuffer)
     {
         HRESULT rc;
         BYTE *address = 0;
-        rc = mFramebuffer->COMGETTER(Address) (&address);
+        rc = pFramebuffer->COMGETTER(Address) (&address);
         AssertComRC (rc);
         ULONG lineSize = 0;
-        rc = mFramebuffer->COMGETTER(LineSize) (&lineSize);
+        rc = pFramebuffer->COMGETTER(LineSize) (&lineSize);
         AssertComRC (rc);
         ULONG colorDepth = 0;
-        rc = mFramebuffer->COMGETTER(ColorDepth) (&colorDepth);
+        rc = pFramebuffer->COMGETTER(ColorDepth) (&colorDepth);
         AssertComRC (rc);
         ULONG width = 0;
-        rc = mFramebuffer->COMGETTER(Width) (&width);
+        rc = pFramebuffer->COMGETTER(Width) (&width);
         AssertComRC (rc);
         ULONG height = 0;
-        rc = mFramebuffer->COMGETTER(Height) (&height);
+        rc = pFramebuffer->COMGETTER(Height) (&height);
         AssertComRC (rc);
 
@@ -1679,5 +1855,5 @@
              mLastHeight != (int) height))
         {
-            handleDisplayResize (mLastColorDepth,
+            handleDisplayResize (VBOX_VIDEO_PRIMARY_SCREEN, mLastColorDepth,
                                  mLastAddress,
                                  mLastLineSize,
@@ -1713,10 +1889,11 @@
 /* static */
 DECLCALLBACK(int) Display::changeFramebuffer (Display *that, IFramebuffer *aFB,
-                                              bool aInternal)
-{
-    LogFlowFunc (("\n"));
+                                              bool aInternal, unsigned uScreenId)
+{
+    LogFlowFunc (("uScreenId = %d\n", uScreenId));
 
     AssertReturn (that, VERR_INVALID_PARAMETER);
     AssertReturn (aFB || aInternal, VERR_INVALID_PARAMETER);
+    AssertReturn (uScreenId >= 0 && uScreenId < that->mcMonitors, VERR_INVALID_PARAMETER);
 
     /// @todo (r=dmik) AutoCaller
@@ -1724,5 +1901,7 @@
     AutoLock alock (that);
 
-    that->mFramebuffer = aFB;
+    DISPLAYFBINFO *pDisplayFBInfo = &that->maFramebuffers[uScreenId];
+    pDisplayFBInfo->pFramebuffer = aFB;
+
     that->mInternalFramebuffer = aInternal;
     that->mSupportedAccelOps = 0;
@@ -1748,7 +1927,5 @@
     }
 
-    that->mParent->consoleVRDPServer()->
-        SetFramebuffer (aFB, aFB ? VRDP_EXTERNAL_FRAMEBUFFER :
-                                   VRDP_INTERNAL_FRAMEBUFFER);
+    that->mParent->consoleVRDPServer()->SendResize ();
 
     that->updateDisplayData (true /* aCheckParams */);
@@ -1758,5 +1935,5 @@
 
 /**
- * Handle display resize event.
+ * Handle display resize event issued by the VGA device for the primary screen.
  *
  * @see PDMIDISPLAYCONNECTOR::pfnResize
@@ -1770,5 +1947,5 @@
                   bpp, pvVRAM, cbLine, cx, cy));
 
-    return pDrv->pDisplay->handleDisplayResize(bpp, pvVRAM, cbLine, cx, cy);
+    return pDrv->pDisplay->handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy);
 }
 
@@ -1816,89 +1993,99 @@
     Display *pDisplay = pDrv->pDisplay;
 
-    /* Check the resize status. The status can be checked normally because
-     * the status affects only the EMT.
-     */
-    uint32_t u32ResizeStatus = pDisplay->mu32ResizeStatus;
-
-    if (u32ResizeStatus == ResizeStatus_UpdateDisplayData)
-    {
-        LogFlowFunc (("ResizeStatus_UpdateDisplayData\n"));
-        /* The framebuffer was resized and display data need to be updated. */
-        pDisplay->handleResizeCompletedEMT ();
-        /* Continue with normal processing because the status here is ResizeStatus_Void. */
-        Assert (pDisplay->mu32ResizeStatus == ResizeStatus_Void);
-        /* Repaint the display because VM continued to run during the framebuffer resize. */
-        if (!pDisplay->mFramebuffer.isNull())
-            pDrv->pUpPort->pfnUpdateDisplayAll(pDrv->pUpPort);
-        /* Ignore the refresh to replay the logic. */
-        return;
-    }
-    else if (u32ResizeStatus == ResizeStatus_InProgress)
-    {
-        /* The framebuffer is being resized. Do not call the VGA device back. Immediately return. */
-        LogFlowFunc (("ResizeStatus_InProcess\n"));
-        return;
-    }
-
-    if (pDisplay->mFramebuffer.isNull())
-    {
-        /*
-         *  Do nothing in the "black hole" mode to avoid copying guest
-         *  video memory to the frame buffer
+    unsigned uScreenId;
+    for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
+    {
+        DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
+
+        /* Check the resize status. The status can be checked normally because
+         * the status affects only the EMT.
          */
-    }
-    else
-    {
-        if (pDisplay->mfPendingVideoAccelEnable)
-        {
-            /* Acceleration was enabled while machine was not yet running
-             * due to restoring from saved state. Update entire display and
-             * actually enable acceleration.
+        uint32_t u32ResizeStatus = pFBInfo->u32ResizeStatus;
+
+        if (u32ResizeStatus == ResizeStatus_UpdateDisplayData)
+        {
+            LogFlowFunc (("ResizeStatus_UpdateDisplayData %d\n", uScreenId));
+            /* The framebuffer was resized and display data need to be updated. */
+            pDisplay->handleResizeCompletedEMT ();
+            /* Continue with normal processing because the status here is ResizeStatus_Void. */
+            Assert (pFBInfo->u32ResizeStatus == ResizeStatus_Void);
+            if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
+            {
+                /* Repaint the display because VM continued to run during the framebuffer resize. */
+                if (!pFBInfo->pFramebuffer.isNull())
+                    pDrv->pUpPort->pfnUpdateDisplayAll(pDrv->pUpPort);
+            }
+            /* Ignore the refresh for the screen to replay the logic. */
+            continue;
+        }
+        else if (u32ResizeStatus == ResizeStatus_InProgress)
+        {
+            /* The framebuffer is being resized. Do not call the VGA device back. Immediately return. */
+            LogFlowFunc (("ResizeStatus_InProcess\n"));
+            continue;
+        }
+
+        if (pFBInfo->pFramebuffer.isNull())
+        {
+            /*
+             *  Do nothing in the "black hole" mode to avoid copying guest
+             *  video memory to the frame buffer
              */
-            Assert(pDisplay->mpPendingVbvaMemory);
-
-            /* Acceleration can not be yet enabled.*/
-            Assert(pDisplay->mpVbvaMemory == NULL);
-            Assert(!pDisplay->mfVideoAccelEnabled);
-
-            if (pDisplay->mfMachineRunning)
+        }
+        else
+        {
+            if (pDisplay->mfPendingVideoAccelEnable)
             {
-                pDisplay->VideoAccelEnable (pDisplay->mfPendingVideoAccelEnable,
-                                            pDisplay->mpPendingVbvaMemory);
-
-                /* Reset the pending state. */
-                pDisplay->mfPendingVideoAccelEnable = false;
-                pDisplay->mpPendingVbvaMemory = NULL;
-            }
-        }
-        else
-        {
-            Assert(pDisplay->mpPendingVbvaMemory == NULL);
-
-            if (pDisplay->mfVideoAccelEnabled)
-            {
-                Assert(pDisplay->mpVbvaMemory);
-                pDisplay->VideoAccelFlush ();
+                /* Acceleration was enabled while machine was not yet running
+                 * due to restoring from saved state. Update entire display and
+                 * actually enable acceleration.
+                 */
+                Assert(pDisplay->mpPendingVbvaMemory);
+
+                /* Acceleration can not be yet enabled.*/
+                Assert(pDisplay->mpVbvaMemory == NULL);
+                Assert(!pDisplay->mfVideoAccelEnabled);
+
+                if (pDisplay->mfMachineRunning)
+                {
+                    pDisplay->VideoAccelEnable (pDisplay->mfPendingVideoAccelEnable,
+                                                pDisplay->mpPendingVbvaMemory);
+
+                    /* Reset the pending state. */
+                    pDisplay->mfPendingVideoAccelEnable = false;
+                    pDisplay->mpPendingVbvaMemory = NULL;
+                }
             }
             else
             {
-                Assert(pDrv->Connector.pu8Data);
-                pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
+                Assert(pDisplay->mpPendingVbvaMemory == NULL);
+
+                if (pDisplay->mfVideoAccelEnabled)
+                {
+                    Assert(pDisplay->mpVbvaMemory);
+                    pDisplay->VideoAccelFlush ();
+                }
+                else
+                {
+                    Assert(pDrv->Connector.pu8Data);
+                    pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
+                }
             }
-        }
 #ifdef VRDP_MC
-        /* Inform to VRDP server that the current display update sequence is
-         * completed. At this moment the framebuffer memory contains a definite
-         * image, that is synchronized with the orders already sent to VRDP client.
-         * The server can now process redraw requests from clients or initial
-         * fullscreen updates for new clients.
-         */
-        Assert (pDisplay->mParent && pDisplay->mParent->consoleVRDPServer());
-        pDisplay->mParent->consoleVRDPServer()->SendUpdate (NULL, 0);
+            /* Inform to VRDP server that the current display update sequence is
+             * completed. At this moment the framebuffer memory contains a definite
+             * image, that is synchronized with the orders already sent to VRDP client.
+             * The server can now process redraw requests from clients or initial
+             * fullscreen updates for new clients.
+             */
+            Assert (pDisplay->mParent && pDisplay->mParent->consoleVRDPServer());
+            pDisplay->mParent->consoleVRDPServer()->SendUpdate (uScreenId, NULL, 0);
 #endif /* VRDP_MC */
+        }
     }
 
 #ifdef DEBUG_sunlover
     STAM_PROFILE_STOP(&StatDisplayRefresh, a);
+    LogFlowFunc (("leave\n"));
 #endif /* DEBUG_sunlover */
 }
@@ -1934,4 +2121,197 @@
     /* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */
     pDrv->pDisplay->VideoAccelEnable (false, NULL);
+}
+
+/**
+ * Adapter information change notification.
+ *
+ * @see PDMIDISPLAYCONNECTOR::pfnProcessAdapterData
+ */
+DECLCALLBACK(void) Display::displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, uint32_t u32VRAMSize)
+{
+    PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
+
+    if (pvVRAM == NULL)
+    {
+        unsigned i;
+        for (i = 0; i < pDrv->pDisplay->mcMonitors; i++)
+        {
+            DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[i];
+
+            pFBInfo->u32Offset = 0;
+            pFBInfo->u32MaxFramebufferSize = 0;
+            pFBInfo->u32InformationSize = 0;
+        }
+    }
+    else
+    {
+         uint8_t *pu8 = (uint8_t *)pvVRAM;
+         pu8 += u32VRAMSize - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
+         
+         // @todo
+         uint8_t *pu8End = pu8 + VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
+
+         VBOXVIDEOINFOHDR *pHdr;
+    
+         for (;;)
+         {
+             pHdr = (VBOXVIDEOINFOHDR *)pu8;
+             pu8 += sizeof (VBOXVIDEOINFOHDR);
+             
+             if (pu8 >= pu8End)
+             {
+                 LogRel(("VBoxVideo: Guest adapter information overflow!!!\n"));
+                 break;
+             }
+
+             if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_DISPLAY)
+             {
+                 if (pHdr->u16Length != sizeof (VBOXVIDEOINFODISPLAY))
+                 {
+                     LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "DISPLAY", pHdr->u16Length));
+                     break;
+                 }
+
+                 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8;
+
+                 if (pDisplay->u32Index >= pDrv->pDisplay->mcMonitors)
+                 {
+                     LogRel(("VBoxVideo: Guest adapter information invalid display index %d!!!\n", pDisplay->u32Index));
+                     break;
+                 }
+
+                 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[pDisplay->u32Index];
+
+                 pFBInfo->u32Offset = pDisplay->u32Offset;
+                 pFBInfo->u32MaxFramebufferSize = pDisplay->u32FramebufferSize;
+                 pFBInfo->u32InformationSize = pDisplay->u32InformationSize;
+
+                 LogFlow(("VBOX_VIDEO_INFO_TYPE_DISPLAY: %d: at 0x%08X, size 0x%08X, info 0x%08X\n", pDisplay->u32Index, pDisplay->u32Offset, pDisplay->u32FramebufferSize, pDisplay->u32InformationSize));
+             }
+             else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
+             {
+                 if (pHdr->u16Length != 0)
+                 {
+                     LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
+                     break;
+                 }
+
+                 break;
+             }
+             else
+             {
+                 LogRel(("Guest adapter information contains unsupported type %d\n", pHdr->u8Type));
+             }
+
+             pu8 += pHdr->u16Length;
+         }
+    }
+}
+
+/**
+ * Display information change notification.
+ *
+ * @see PDMIDISPLAYCONNECTOR::pfnProcessDisplayData
+ */
+DECLCALLBACK(void) Display::displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, unsigned uScreenId)
+{
+    PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
+
+    if (uScreenId >= pDrv->pDisplay->mcMonitors)
+    {
+        LogRel(("VBoxVideo: Guest display information invalid display index %d!!!\n", uScreenId));
+        return;
+    }
+
+    /* Get the display information strcuture. */
+    DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[uScreenId];
+
+    uint8_t *pu8 = (uint8_t *)pvVRAM;
+    pu8 += pFBInfo->u32Offset + pFBInfo->u32MaxFramebufferSize;
+         
+    // @todo
+    uint8_t *pu8End = pu8 + pFBInfo->u32InformationSize;
+
+    VBOXVIDEOINFOHDR *pHdr;
+    
+    for (;;)
+    {
+        pHdr = (VBOXVIDEOINFOHDR *)pu8;
+        pu8 += sizeof (VBOXVIDEOINFOHDR);
+             
+        if (pu8 >= pu8End)
+        {
+            LogRel(("VBoxVideo: Guest display information overflow!!!\n"));
+            break;
+        }
+
+        if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_SCREEN)
+        {
+            if (pHdr->u16Length != sizeof (VBOXVIDEOINFOSCREEN))
+            {
+                LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "SCREEN", pHdr->u16Length));
+                break;
+            }
+
+            VBOXVIDEOINFOSCREEN *pScreen = (VBOXVIDEOINFOSCREEN *)pu8;
+
+            pFBInfo->xOrigin = pScreen->xOrigin;
+            pFBInfo->yOrigin = pScreen->yOrigin;
+
+            pFBInfo->w = pScreen->u16Width;
+            pFBInfo->h = pScreen->u16Height;
+
+            LogFlow(("VBOX_VIDEO_INFO_TYPE_SCREEN: (%p) %d: at %d,%d, linesize 0x%X, size %dx%d, bpp %d, flags 0x%02X\n",
+                     pHdr, uScreenId, pScreen->xOrigin, pScreen->yOrigin, pScreen->u32LineSize, pScreen->u16Width, pScreen->u16Height, pScreen->bitsPerPixel, pScreen->u8Flags));
+
+            if (uScreenId != VBOX_VIDEO_PRIMARY_SCREEN)
+            {
+                /* Primary screen resize is initiated by the VGA device. */
+                pDrv->pDisplay->handleDisplayResize(uScreenId, pScreen->bitsPerPixel, (uint8_t *)pvVRAM + pFBInfo->u32Offset, pScreen->u32LineSize, pScreen->u16Width, pScreen->u16Height);
+            }
+        }
+        else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
+        {
+            if (pHdr->u16Length != 0)
+            {
+                LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
+                break;
+            }
+
+            break;
+        }
+        else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_HOST_EVENTS)
+        {
+            if (pHdr->u16Length != sizeof (VBOXVIDEOINFOHOSTEVENTS))
+            {
+                LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "HOST_EVENTS", pHdr->u16Length));
+                break;
+            }
+
+            VBOXVIDEOINFOHOSTEVENTS *pHostEvents = (VBOXVIDEOINFOHOSTEVENTS *)pu8;
+
+            pFBInfo->pHostEvents = pHostEvents;
+
+            LogFlow(("VBOX_VIDEO_INFO_TYPE_HOSTEVENTS: (%p)\n",
+                     pHostEvents));
+        }
+        else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_LINK)
+        {
+            if (pHdr->u16Length != sizeof (VBOXVIDEOINFOLINK))
+            {
+                LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "LINK", pHdr->u16Length));
+                break;
+            }
+
+            VBOXVIDEOINFOLINK *pLink = (VBOXVIDEOINFOLINK *)pu8;
+            pu8 += pLink->i32Offset;
+        }
+        else
+        {
+            LogRel(("Guest display information contains unsupported type %d\n", pHdr->u8Type));
+        }
+
+        pu8 += pHdr->u16Length;
+    }
 }
 
@@ -2022,4 +2402,6 @@
     pData->Connector.pfnReset           = Display::displayResetCallback;
     pData->Connector.pfnLFBModeChange   = Display::displayLFBModeChangeCallback;
+    pData->Connector.pfnProcessAdapterData = Display::displayProcessAdapterDataCallback;
+    pData->Connector.pfnProcessDisplayData = Display::displayProcessDisplayDataCallback;
 
     /*
Index: trunk/src/VBox/Main/FramebufferImpl.cpp
===================================================================
--- trunk/src/VBox/Main/FramebufferImpl.cpp	(revision 3127)
+++ trunk/src/VBox/Main/FramebufferImpl.cpp	(revision 3153)
@@ -149,5 +149,5 @@
 
 STDMETHODIMP
-InternalFramebuffer::RequestResize(FramebufferPixelFormat_T pixelFormat, BYTE *vram,
+InternalFramebuffer::RequestResize(ULONG iScreenId, FramebufferPixelFormat_T pixelFormat, BYTE *vram,
                                    ULONG lineSize, ULONG w, ULONG h,
                                    BOOL *finished)
Index: trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 3127)
+++ trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 3153)
@@ -6048,5 +6048,5 @@
     <interface
         name="IFramebuffer" extends="$unknown"
-        uuid="4481F27F-5C79-48d9-86C1-A2EC6747034D"
+        uuid="9f3eba23-6a75-49f3-93e7-cad00fb605f6"
         wsmap="suppress"
     >
@@ -6168,4 +6168,7 @@
                 </note>
             </desc>
+            <param name="screenId" type="unsigned long" dir="in">
+                <desc>The value to be used in the <link to="IDisplay::resizeCompleted()"/> call.</desc>
+            </param>
             <param name="pixelFormat" type="FramebufferPixelFormat" dir="in">
                 <desc>Pixel format of the surface (BPP and layout)</desc>
@@ -6298,5 +6301,5 @@
     <interface
         name="IDisplay" extends="$unknown"
-        uuid="0a6a7746-5469-47e4-9a00-8b1ea28891b8"
+        uuid="e740a435-88d1-4f14-b9ca-a1b30e2c5038"
         wsmap="suppress"
     >
@@ -6341,4 +6344,22 @@
             </desc>
             <param name="framebuffer" type="IFramebuffer" dir="in"/>
+        </method>
+
+        <method name="setFramebuffer">
+            <desc>
+                Sets the framebuffer for given screen.
+            </desc>
+            <param name="screenId" type="unsigned long" dir="in"/>
+            <param name="framebuffer" type="IFramebuffer" dir="in"/>
+        </method>
+
+        <method name="queryFramebuffer">
+            <desc>
+                Queries the framebuffer for given screen.
+            </desc>
+            <param name="screenId" type="unsigned long" dir="in"/>
+            <param name="framebuffer" type="IFramebuffer" dir="out"/>
+            <param name="xOrigin" type="long" dir="out"/>
+            <param name="yOrigin" type="long" dir="out"/>
         </method>
 
@@ -6396,4 +6417,5 @@
                 Signals that a framebuffer has completed the resize operation.
             </desc>
+            <param name="screenId" type="unsigned long" dir="in"/>
         </method>
 
Index: trunk/src/VBox/Main/include/ConsoleVRDPServer.h
===================================================================
--- trunk/src/VBox/Main/include/ConsoleVRDPServer.h	(revision 3127)
+++ trunk/src/VBox/Main/include/ConsoleVRDPServer.h	(revision 3153)
@@ -79,7 +79,7 @@
      * Forwarders to VRDP server library.
      */
-    void SendUpdate (void *pvUpdate, uint32_t cbUpdate) const;
+    void SendUpdate (unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const;
     void SendResize (void) const;
-    void SendUpdateBitmap (uint32_t x, uint32_t y, uint32_t w, uint32_t h) const;
+    void SendUpdateBitmap (unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const;
     void SetFramebuffer (IFramebuffer *framebuffer, uint32_t fFlags) const;
 
@@ -113,5 +113,5 @@
     static void (VBOXCALL *mpfnVRDPSetCallback)     (HVRDPSERVER hServer, VRDPSERVERCALLBACK *pcallback, void *pvUser);
     static void (VBOXCALL *mpfnVRDPShutdownServer)  (HVRDPSERVER hServer);
-    static void (VBOXCALL *mpfnVRDPSendUpdateBitmap)(HVRDPSERVER hServer, unsigned x, unsigned y, unsigned w, unsigned h);
+    static void (VBOXCALL *mpfnVRDPSendUpdateBitmap)(HVRDPSERVER hServer, unsigned uScreenId, unsigned x, unsigned y, unsigned w, unsigned h);
     static void (VBOXCALL *mpfnVRDPSendResize)      (HVRDPSERVER hServer);
     static void (VBOXCALL *mpfnVRDPSendAudioSamples)(HVRDPSERVER hserver, void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format);
@@ -122,5 +122,5 @@
     static void (VBOXCALL *mpfnVRDPSendUSBRequest)  (HVRDPSERVER hserver, void *pvParms, uint32_t cbParms);
 #endif /* VRDP_MC */
-    static void (VBOXCALL *mpfnVRDPSendUpdate)      (HVRDPSERVER hServer, void *pvUpdate, uint32_t cbUpdate);
+    static void (VBOXCALL *mpfnVRDPSendUpdate)      (HVRDPSERVER hServer, unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate);
     static void (VBOXCALL *mpfnVRDPQueryInfo)       (HVRDPSERVER hserver, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut);
     static void (VBOXCALL *mpfnVRDPClipboard)       (HVRDPSERVER hserver, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData, uint32_t *pcbActualRead);
Index: trunk/src/VBox/Main/include/DisplayImpl.h
===================================================================
--- trunk/src/VBox/Main/include/DisplayImpl.h	(revision 3127)
+++ trunk/src/VBox/Main/include/DisplayImpl.h	(revision 3153)
@@ -24,9 +24,48 @@
 
 #include "VirtualBoxBase.h"
+#include "SchemaDefs.h"
 #include <iprt/semaphore.h>
 #include <VBox/pdm.h>
 #include <VBox/VBoxGuest.h>
+#include <VBox/VBoxVideo.h>
 
 class Console;
+
+enum {
+    ResizeStatus_Void,
+    ResizeStatus_InProgress,
+    ResizeStatus_UpdateDisplayData
+};
+
+typedef struct _DISPLAYFBINFO
+{
+    uint32_t u32Offset;
+    uint32_t u32MaxFramebufferSize;
+    uint32_t u32InformationSize;
+
+    ComPtr<IFramebuffer> pFramebuffer;
+
+    LONG xOrigin;
+    LONG yOrigin;
+
+    ULONG w;
+    ULONG h;
+
+    VBOXVIDEOINFOHOSTEVENTS *pHostEvents;
+
+    volatile uint32_t u32ResizeStatus;
+    
+    /* The Framebuffer has default format and must be updates immediately. */
+    bool fDefaultFormat;
+    
+    struct {
+        /* The rectangle that includes all dirty rectangles. */
+        int32_t xLeft;
+        int32_t xRight;
+        int32_t yTop;
+        int32_t yBottom;
+    } dirtyRect;
+
+} DISPLAYFBINFO;
 
 class ATL_NO_VTABLE Display :
@@ -59,9 +98,9 @@
 
     // public methods only for internal purposes
-    int handleDisplayResize (uint32_t bpp, void *pvVRAM, uint32_t cbLine, int w, int h);
+    int handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM, uint32_t cbLine, int w, int h);
     void handleDisplayUpdate (int x, int y, int cx, int cy);
     IFramebuffer *getFramebuffer()
     {
-        return mFramebuffer;
+        return maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer;
     }
 
@@ -138,9 +177,11 @@
     STDMETHOD(UnlockFramebuffer)();
     STDMETHOD(RegisterExternalFramebuffer)(IFramebuffer *frameBuf);
+    STDMETHOD(SetFramebuffer)(ULONG aScreenId, IFramebuffer * aFramebuffer);
+    STDMETHOD(QueryFramebuffer)(ULONG aScreenId, IFramebuffer * * aFramebuffer, LONG * aXOrigin, LONG * aYOrigin);
     STDMETHOD(SetVideoModeHint)(ULONG width, ULONG height, ULONG colorDepth, ULONG display);
     STDMETHOD(TakeScreenShot)(BYTE *address, ULONG width, ULONG height);
     STDMETHOD(DrawToScreen)(BYTE *address, ULONG x, ULONG y, ULONG width, ULONG height);
     STDMETHOD(InvalidateAndUpdate)();
-    STDMETHOD(ResizeCompleted)();
+    STDMETHOD(ResizeCompleted)(ULONG aScreenId);
     STDMETHOD(UpdateCompleted)();
 
@@ -155,5 +196,5 @@
 
     static DECLCALLBACK(int) changeFramebuffer (Display *that, IFramebuffer *aFB,
-                                                bool aInternal);
+                                                bool aInternal, unsigned uScreenId);
 
     static DECLCALLBACK(void*) drvQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface);
@@ -166,4 +207,6 @@
     static DECLCALLBACK(void)  displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface);
     static DECLCALLBACK(void)  displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled);
+    static DECLCALLBACK(void)  displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, uint32_t u32VRAMSize);
+    static DECLCALLBACK(void)  displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, unsigned uScreenId);
 
     ComObjPtr <Console, ComWeakRef> mParent;
@@ -175,5 +218,9 @@
     bool                    mfVMMDevInited;
     bool mInternalFramebuffer;
-    ComPtr<IFramebuffer> mFramebuffer;
+//    ComPtr<IFramebuffer> mFramebuffer;
+
+    unsigned mcMonitors;
+    DISPLAYFBINFO maFramebuffers[SchemaDefs::MaxGuestMonitors];
+
     bool mFramebufferOpened;
     /** bitmask of acceleration operations supported by current framebuffer */
@@ -206,11 +253,5 @@
 
     void handleResizeCompletedEMT (void);
-    volatile uint32_t mu32ResizeStatus;
-    
-    enum {
-        ResizeStatus_Void,
-        ResizeStatus_InProgress,
-        ResizeStatus_UpdateDisplayData
-    };
+//    volatile uint32_t mu32ResizeStatus;
 };
 
Index: trunk/src/VBox/Main/include/FramebufferImpl.h
===================================================================
--- trunk/src/VBox/Main/include/FramebufferImpl.h	(revision 3127)
+++ trunk/src/VBox/Main/include/FramebufferImpl.h	(revision 3153)
@@ -63,5 +63,5 @@
                             ULONG w, ULONG h,
                             BOOL *finished);
-    STDMETHOD(RequestResize)(FramebufferPixelFormat_T pixelFormat, BYTE *vram,
+    STDMETHOD(RequestResize)(ULONG uScreenId, FramebufferPixelFormat_T pixelFormat, BYTE *vram,
                              ULONG lineSize, ULONG w, ULONG h,
                              BOOL *finished);
