[libvirt] [PATCH 62/66] vbox: Rewrite vboxDomainScreenshot

Taowei uaedante at gmail.com
Mon Aug 11 10:07:05 UTC 2014


---
 src/vbox/vbox_common.c        |  130 ++++++++++++++++++++++++++++
 src/vbox/vbox_common.h        |    1 +
 src/vbox/vbox_tmpl.c          |  190 ++++++++++++-----------------------------
 src/vbox/vbox_uniformed_api.h |   23 ++++-
 4 files changed, 208 insertions(+), 136 deletions(-)

diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
index 505f1cd..d3735ac 100644
--- a/src/vbox/vbox_common.c
+++ b/src/vbox/vbox_common.c
@@ -19,6 +19,7 @@
 #include <config.h>
 
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "internal.h"
 #include "datatypes.h"
@@ -32,6 +33,8 @@
 #include "virtime.h"
 #include "snapshot_conf.h"
 #include "vbox_snapshot_conf.h"
+#include "fdstream.h"
+#include "configmake.h"
 
 #include "vbox_common.h"
 #include "vbox_uniformed_api.h"
@@ -7133,3 +7136,130 @@ int vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
     gVBoxAPI.UISession.Close(data->vboxSession);
     return ret;
 }
+
+char *
+vboxDomainScreenshot(virDomainPtr dom,
+                     virStreamPtr st,
+                     unsigned int screen,
+                     unsigned int flags)
+{
+    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
+    IConsole *console = NULL;
+    vboxIIDUnion iid;
+    IMachine *machine = NULL;
+    nsresult rc;
+    char *tmp;
+    int tmp_fd = -1;
+    unsigned int max_screen;
+
+    if (!gVBoxAPI.supportScreenshot) {
+        virReportError(VIR_ERR_NO_SUPPORT, "%s",
+                       _("virDomainScreenshot don't support for current vbox version"));
+        return NULL;
+    }
+
+    virCheckFlags(0, NULL);
+
+    if (openSessionForMachine(data, dom->uuid, &iid, &machine, false) < 0)
+        return NULL;
+
+    rc = gVBoxAPI.UIMachine.GetMonitorCount(machine, &max_screen);
+    if (NS_FAILED(rc)) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("unable to get monitor count"));
+        VBOX_RELEASE(machine);
+        return NULL;
+    }
+
+    if (screen >= max_screen) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("screen ID higher than monitor "
+                         "count (%d)"), max_screen);
+        VBOX_RELEASE(machine);
+        return NULL;
+    }
+
+    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
+        VBOX_RELEASE(machine);
+        return NULL;
+    }
+
+    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
+        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
+        VIR_FREE(tmp);
+        VBOX_RELEASE(machine);
+        return NULL;
+    }
+
+
+    rc = gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
+    if (NS_SUCCEEDED(rc)) {
+        rc = gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
+        if (NS_SUCCEEDED(rc) && console) {
+            IDisplay *display = NULL;
+
+            gVBoxAPI.UIConsole.GetDisplay(console, &display);
+
+            if (display) {
+                PRUint32 width, height, bitsPerPixel;
+                PRUint32 screenDataSize;
+                PRUint8 *screenData;
+                PRInt32 xOrigin, yOrigin;
+
+                rc = gVBoxAPI.UIDisplay.GetScreenResolution(display, screen,
+                                                            &width, &height,
+                                                            &bitsPerPixel,
+                                                            &xOrigin, &yOrigin);
+
+                if (NS_FAILED(rc) || !width || !height) {
+                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                                   _("unable to get screen resolution"));
+                    goto endjob;
+                }
+
+                rc = gVBoxAPI.UIDisplay.TakeScreenShotPNGToArray(display, screen,
+                                                                 width, height,
+                                                                 &screenDataSize,
+                                                                 &screenData);
+                if (NS_FAILED(rc)) {
+                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                                   _("failed to take screenshot"));
+                    goto endjob;
+                }
+
+                if (safewrite(tmp_fd, (char *) screenData,
+                              screenDataSize) < 0) {
+                    virReportSystemError(errno, _("unable to write data "
+                                                  "to '%s'"), tmp);
+                    goto endjob;
+                }
+
+                if (VIR_CLOSE(tmp_fd) < 0) {
+                    virReportSystemError(errno, _("unable to close %s"), tmp);
+                    goto endjob;
+                }
+
+                if (VIR_STRDUP(ret, "image/png") < 0)
+                    goto endjob;
+
+                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
+                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                                   _("unable to open stream"));
+                    VIR_FREE(ret);
+                }
+ endjob:
+                VIR_FREE(screenData);
+                VBOX_RELEASE(display);
+            }
+            VBOX_RELEASE(console);
+        }
+        gVBoxAPI.UISession.Close(data->vboxSession);
+    }
+
+    VIR_FORCE_CLOSE(tmp_fd);
+    unlink(tmp);
+    VIR_FREE(tmp);
+    VBOX_RELEASE(machine);
+    vboxIIDUnalloc(&iid);
+    return ret;
+}
diff --git a/src/vbox/vbox_common.h b/src/vbox/vbox_common.h
index 15bf8e2..b5a0353 100644
--- a/src/vbox/vbox_common.h
+++ b/src/vbox/vbox_common.h
@@ -301,5 +301,6 @@ typedef nsISupports IMediumAttachment;
 typedef nsISupports IStorageController;
 typedef nsISupports ISharedFolder;
 typedef nsISupports ISnapshot;
+typedef nsISupports IDisplay;
 
 #endif /* VBOX_COMMON_H */
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index 044e6d6..82c45ad 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -3732,141 +3732,6 @@ static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
     return ret;
 }
 
-#if VBOX_API_VERSION >= 4000000
-static char *
-vboxDomainScreenshot(virDomainPtr dom,
-                     virStreamPtr st,
-                     unsigned int screen,
-                     unsigned int flags)
-{
-    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
-    IConsole *console = NULL;
-    vboxIID iid = VBOX_IID_INITIALIZER;
-    IMachine *machine = NULL;
-    nsresult rc;
-    char *tmp;
-    int tmp_fd = -1;
-    unsigned int max_screen;
-
-    virCheckFlags(0, NULL);
-
-    vboxIIDFromUUID(&iid, dom->uuid);
-    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
-    if (NS_FAILED(rc)) {
-        virReportError(VIR_ERR_NO_DOMAIN, "%s",
-                       _("no domain with matching uuid"));
-        return NULL;
-    }
-
-    rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
-    if (NS_FAILED(rc)) {
-        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                       _("unable to get monitor count"));
-        VBOX_RELEASE(machine);
-        return NULL;
-    }
-
-    if (screen >= max_screen) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("screen ID higher than monitor "
-                         "count (%d)"), max_screen);
-        VBOX_RELEASE(machine);
-        return NULL;
-    }
-
-    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
-        VBOX_RELEASE(machine);
-        return NULL;
-    }
-
-    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
-        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
-        VIR_FREE(tmp);
-        VBOX_RELEASE(machine);
-        return NULL;
-    }
-
-
-    rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
-    if (NS_SUCCEEDED(rc)) {
-        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
-        if (NS_SUCCEEDED(rc) && console) {
-            IDisplay *display = NULL;
-
-            console->vtbl->GetDisplay(console, &display);
-
-            if (display) {
-                PRUint32 width, height, bitsPerPixel;
-                PRUint32 screenDataSize;
-                PRUint8 *screenData;
-# if VBOX_API_VERSION >= 4003000
-                PRInt32 xOrigin, yOrigin;
-# endif
-
-                rc = display->vtbl->GetScreenResolution(display, screen,
-                                                        &width, &height,
-# if VBOX_API_VERSION < 4003000
-                                                        &bitsPerPixel);
-# else
-                                                        &bitsPerPixel,
-                                                        &xOrigin, &yOrigin);
-# endif
-
-                if (NS_FAILED(rc) || !width || !height) {
-                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                                   _("unable to get screen resolution"));
-                    goto endjob;
-                }
-
-                rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
-                                                             width, height,
-                                                             &screenDataSize,
-                                                             &screenData);
-                if (NS_FAILED(rc)) {
-                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                                   _("failed to take screenshot"));
-                    goto endjob;
-                }
-
-                if (safewrite(tmp_fd, (char *) screenData,
-                              screenDataSize) < 0) {
-                    virReportSystemError(errno, _("unable to write data "
-                                                  "to '%s'"), tmp);
-                    goto endjob;
-                }
-
-                if (VIR_CLOSE(tmp_fd) < 0) {
-                    virReportSystemError(errno, _("unable to close %s"), tmp);
-                    goto endjob;
-                }
-
-                if (VIR_STRDUP(ret, "image/png") < 0)
-                    goto endjob;
-
-                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
-                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                                   _("unable to open stream"));
-                    VIR_FREE(ret);
-                }
- endjob:
-                VIR_FREE(screenData);
-                VBOX_RELEASE(display);
-            }
-            VBOX_RELEASE(console);
-        }
-        VBOX_SESSION_CLOSE();
-    }
-
-    VIR_FORCE_CLOSE(tmp_fd);
-    unlink(tmp);
-    VIR_FREE(tmp);
-    VBOX_RELEASE(machine);
-    vboxIIDUnalloc(&iid);
-    return ret;
-}
-#endif /* VBOX_API_VERSION >= 4000000 */
-
-
 #define MATCH(FLAG) (flags & (FLAG))
 static int
 vboxConnectListAllDomains(virConnectPtr conn,
@@ -5474,6 +5339,12 @@ _consoleDeleteSnapshot(IConsole *console, vboxIIDUnion *iidu, IProgress **progre
 }
 
 static nsresult
+_consoleGetDisplay(IConsole *console, IDisplay **display)
+{
+    return console->vtbl->GetDisplay(console, display);
+}
+
+static nsresult
 _progressWaitForCompletion(IProgress *progress, PRInt32 timeout)
 {
     return progress->vtbl->WaitForCompletion(progress, timeout);
@@ -6339,6 +6210,46 @@ _snapshotGetOnline(ISnapshot *snapshot, PRBool *online)
     return snapshot->vtbl->GetOnline(snapshot, online);
 }
 
+static nsresult
+_displayGetScreenResolution(IDisplay *display ATTRIBUTE_UNUSED,
+                            PRUint32 screenId ATTRIBUTE_UNUSED,
+                            PRUint32 *width ATTRIBUTE_UNUSED,
+                            PRUint32 *height ATTRIBUTE_UNUSED,
+                            PRUint32 *bitsPerPixel ATTRIBUTE_UNUSED,
+                            PRInt32 *xOrigin ATTRIBUTE_UNUSED,
+                            PRInt32 *yOrigin ATTRIBUTE_UNUSED)
+{
+#if VBOX_API_VERSION < 3002000
+    vboxUnsupported();
+    return 0;
+#elif VBOX_API_VERSION < 4003000
+    return display->vtbl->GetScreenResolution(display, screenId, width,
+                                              height, bitsPerPixel);
+#else /* VBOX_API_VERSION >= 4003000 */
+    return display->vtbl->GetScreenResolution(display, screenId, width,
+                                              height, bitsPerPixel,
+                                              xOrigin, yOrigin);
+#endif /* VBOX_API_VERSION >= 4003000 */
+}
+
+static nsresult
+_displayTakeScreenShotPNGToArray(IDisplay *display ATTRIBUTE_UNUSED,
+                                 PRUint32 screenId ATTRIBUTE_UNUSED,
+                                 PRUint32 width ATTRIBUTE_UNUSED,
+                                 PRUint32 height ATTRIBUTE_UNUSED,
+                                 PRUint32 *screenDataSize ATTRIBUTE_UNUSED,
+                                 PRUint8** screenData ATTRIBUTE_UNUSED)
+{
+#if VBOX_API_VERSION < 4000000
+    vboxUnsupported();
+    return 0;
+#else /* VBOX_API_VERSION >= 4000000 */
+    return display->vtbl->TakeScreenShotPNGToArray(display, screenId, width,
+                                                   height, screenDataSize,
+                                                   screenData);
+#endif /* VBOX_API_VERSION >= 4000000 */
+}
+
 static bool _machineStateOnline(PRUint32 state)
 {
     return ((state >= MachineState_FirstOnline) &&
@@ -6486,6 +6397,7 @@ static vboxUniformedIConsole _UIConsole = {
     .Reset = _consoleReset,
     .TakeSnapshot = _consoleTakeSnapshot,
     .DeleteSnapshot = _consoleDeleteSnapshot,
+    .GetDisplay = _consoleGetDisplay,
 };
 
 static vboxUniformedIProgress _UIProgress = {
@@ -6634,6 +6546,11 @@ static vboxUniformedISnapshot _UISnapshot = {
     .GetOnline = _snapshotGetOnline,
 };
 
+static vboxUniformedIDisplay _UIDisplay = {
+    .GetScreenResolution = _displayGetScreenResolution,
+    .TakeScreenShotPNGToArray = _displayTakeScreenShotPNGToArray,
+};
+
 static uniformedMachineStateChecker _machineStateChecker = {
     .Online = _machineStateOnline,
     .Inactive = _machineStateInactive,
@@ -6685,6 +6602,7 @@ void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI)
     pVBoxAPI->UIStorageController = _UIStorageController;
     pVBoxAPI->UISharedFolder = _UISharedFolder;
     pVBoxAPI->UISnapshot = _UISnapshot;
+    pVBoxAPI->UIDisplay = _UIDisplay;
     pVBoxAPI->machineStateChecker = _machineStateChecker;
 
 #if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
@@ -6704,10 +6622,12 @@ void NAME(InstallUniformedAPI)(vboxUniformedAPI *pVBoxAPI)
     pVBoxAPI->getMachineForSession = 1;
     pVBoxAPI->detachDevicesExplicitly = 0;
     pVBoxAPI->vboxAttachDrivesUseOld = 0;
+    pVBoxAPI->supportScreenshot = 1;
 #else /* VBOX_API_VERSION < 4000000 */
     pVBoxAPI->getMachineForSession = 0;
     pVBoxAPI->detachDevicesExplicitly = 1;
     pVBoxAPI->vboxAttachDrivesUseOld = 1;
+    pVBoxAPI->supportScreenshot = 0;
 #endif /* VBOX_API_VERSION < 4000000 */
 
 #if VBOX_API_VERSION >= 4001000
diff --git a/src/vbox/vbox_uniformed_api.h b/src/vbox/vbox_uniformed_api.h
index 2800b60..7e8f677 100644
--- a/src/vbox/vbox_uniformed_api.h
+++ b/src/vbox/vbox_uniformed_api.h
@@ -273,6 +273,7 @@ typedef struct {
     nsresult (*TakeSnapshot)(IConsole *console, PRUnichar *name,
                              PRUnichar *description, IProgress **progress);
     nsresult (*DeleteSnapshot)(IConsole *console, vboxIIDUnion *iidu, IProgress **progress);
+    nsresult (*GetDisplay)(IConsole *console, IDisplay **display);
 } vboxUniformedIConsole;
 
 /* Functions for IProgress */
@@ -446,6 +447,23 @@ typedef struct {
     nsresult (*GetOnline)(ISnapshot *snapshot, PRBool *online);
 } vboxUniformedISnapshot;
 
+/* Functions for IDisplay */
+typedef struct {
+    nsresult (*GetScreenResolution)(IDisplay *display,
+                                    PRUint32 screenId,
+                                    PRUint32 *width,
+                                    PRUint32 *height,
+                                    PRUint32 *bitsPerPixel,
+                                    PRInt32 *xOrigin,
+                                    PRInt32 *yOrigin);
+    nsresult (*TakeScreenShotPNGToArray)(IDisplay *display,
+                                         PRUint32 screenId,
+                                         PRUint32 width,
+                                         PRUint32 height,
+                                         PRUint32 *screenDataSize,
+                                         PRUint8** screenData);
+} vboxUniformedIDisplay;
+
 typedef struct {
     bool (*Online)(PRUint32 state);
     bool (*Inactive)(PRUint32 state);
@@ -498,6 +516,7 @@ typedef struct {
     vboxUniformedIStorageController UIStorageController;
     vboxUniformedISharedFolder UISharedFolder;
     vboxUniformedISnapshot UISnapshot;
+    vboxUniformedIDisplay UIDisplay;
     uniformedMachineStateChecker machineStateChecker;
     /* vbox API features */
     bool domainEventCallbacks;
@@ -509,6 +528,7 @@ typedef struct {
     bool vboxAttachDrivesUseOld;
     bool oldMediumInterface;
     bool vboxSnapshotRedefine;
+    bool supportScreenshot;
 } vboxUniformedAPI;
 
 /* libvirt API
@@ -599,7 +619,8 @@ int vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
                                unsigned int flags);
 int vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                              unsigned int flags);
-
+char *vboxDomainScreenshot(virDomainPtr dom, virStreamPtr st,
+                           unsigned int screen, unsigned int flags);
 
 /* Version specified functions for installing uniformed API */
 void vbox22InstallUniformedAPI(vboxUniformedAPI *pVBoxAPI);
-- 
1.7.9.5




More information about the libvir-list mailing list