From 2353ceb8d8e5a3eacf5010ca5312af81822445bb Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 4 Jul 2014 11:55:46 +0200
Subject: add qxl_screendump monitor command

RH-Author: Gerd Hoffmann <kraxel@redhat.com>
Message-id: <1375866764-17766-2-git-send-email-kraxel@redhat.com>
Patchwork-id: 53033
O-Subject: [RHEL-7 qemu-kvm PATCH 1/1] add qxl_screendump monitor command
Bugzilla: 903910
RH-Acked-by: Hans de Goede <hdegoede@redhat.com>
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
RH-Acked-by: Michal Novotny <minovotn@redhat.com>

This patch ports the rhel-6 specific qxl_screendump command to rhel-7.
qxl_screendump takes the device id as additional argument and thus can
be used to take screenshots from non-primary displays.

The plan to get that functionality upstream in time failed, so we go for
plan b and carry forward the rhel-6 specific qxl_screendump command.
Thanks to the major console subsystem cleanups which made it upstream
the implementation is (a) alot less hackier than the rhel-6 one and (b)
not qxl-specific any more.  Given that qxl is the only graphic device
which can work as secondary vga card the later is only a theoretical
benefit though ;)

RHEL-6 commit: 1c6074d107dff93c7c7b0edfb5da871504802946

bugzilla: #903910 - RHEL7 does not have equivalent functionality for
__com.redhat_qxl_screendump

Merged patches (2.6.0):
- f12846f __com.redhat_qxl_screendump: add docs

Rebase notes (2.4.0):
- replace QERR_DEVICE_NOT_FOUND with ERROR_CLASS_DEVICE_NOT_FOUND

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hmp-commands.hx  | 14 ++++++++++++++
 hmp.c            | 10 ++++++++++
 hmp.h            |  1 +
 qapi-schema.json | 15 +++++++++++++++
 qmp-commands.hx  | 14 ++++++++++++++
 ui/console.c     | 24 ++++++++++++++++++++++++
 6 files changed, 78 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 4f4f60a..450f1fb 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -266,6 +266,20 @@ Save screen into PPM image @var{filename}.
 ETEXI
 
     {
+        .name       = "__com.redhat_qxl_screendump",
+        .args_type  = "id:s,filename:F",
+        .params     = "id filename",
+        .help       = "save screen from qxl device 'id' into PPM image 'filename'",
+        .mhandler.cmd = hmp___com_redhat_qxl_screen_dump,
+    },
+
+STEXI
+@item __com.redhat_screendump @var{id} @var{filename}
+@findex __com.redhat_screendump
+Save screen from qxl device @var{id} into PPM image @var{filename}.
+ETEXI
+
+    {
         .name       = "logfile",
         .args_type  = "filename:F",
         .params     = "filename",
diff --git a/hmp.c b/hmp.c
index d510236..24b1139 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1791,6 +1791,16 @@ void hmp_screendump(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, &err);
 }
 
+void hmp___com_redhat_qxl_screen_dump(Monitor *mon, const QDict *qdict)
+{
+    const char *id = qdict_get_str(qdict, "id");
+    const char *filename = qdict_get_str(qdict, "filename");
+    Error *err = NULL;
+
+    qmp___com_redhat_qxl_screendump(id, filename, &err);
+    hmp_handle_error(mon, &err);
+}
+
 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
 {
     const char *uri = qdict_get_str(qdict, "uri");
diff --git a/hmp.h b/hmp.h
index 093d65f..e9c3d6c 100644
--- a/hmp.h
+++ b/hmp.h
@@ -91,6 +91,7 @@ void hmp_getfd(Monitor *mon, const QDict *qdict);
 void hmp_closefd(Monitor *mon, const QDict *qdict);
 void hmp_sendkey(Monitor *mon, const QDict *qdict);
 void hmp_screendump(Monitor *mon, const QDict *qdict);
+void hmp___com_redhat_qxl_screen_dump(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
diff --git a/qapi-schema.json b/qapi-schema.json
index 54634c4..0d6ee22 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3181,6 +3181,21 @@
                                        '*logappend': 'bool' } }
 
 ##
+# @__com.redhat_qxl_screendump:
+#
+# Write a PPM of secondary qxl devices to a file.
+#
+# @id: qxl device id
+# @filename: the path of a new PPM file to store the image
+#
+# Returns: Nothing on success
+#
+# Since: never (rhel-only, not upstream)
+##
+{ 'command': '__com.redhat_qxl_screendump', 'data': { 'id' : 'str',
+                                                      'filename': 'str' } }
+
+##
 # @ChardevFile:
 #
 # Configuration info for file chardevs.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index de896a5..8274cb3 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -167,6 +167,20 @@ Example:
 EQMP
 
     {
+        .name       = "__com.redhat_qxl_screendump",
+        .args_type  = "id:s,filename:F",
+        .mhandler.cmd_new = qmp_marshal___com_redhat_qxl_screendump,
+    },
+
+SQMP
+__com.redhat_qxl_screendump
+---------------------------
+
+Save screen from qxl device @var{id} into PPM image @var{filename}.
+
+EQMP
+
+    {
         .name       = "stop",
         .args_type  = "",
         .mhandler.cmd_new = qmp_marshal_stop,
diff --git a/ui/console.c b/ui/console.c
index bf38579..68bda31 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -345,6 +345,30 @@ void qmp_screendump(const char *filename, Error **errp)
     ppm_save(filename, surface, errp);
 }
 
+void qmp___com_redhat_qxl_screendump(const char *id, const char *filename, Error **errp)
+{
+    DeviceState *dev;
+    QemuConsole *con;
+    DisplaySurface *surface;
+
+    dev = qdev_find_recursive(sysbus_get_default(), id);
+    if (NULL == dev) {
+        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+                  "Device '%s' not found", id);
+        return;
+    }
+
+    con = qemu_console_lookup_by_device(dev, 0);
+    if (con == NULL) {
+        error_setg(errp, "Device %s has no QemuConsole attached to it.", id);
+        return;
+    }
+
+    graphic_hw_update(con);
+    surface = qemu_console_surface(con);
+    ppm_save(filename, surface, errp);
+}
+
 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
 {
     if (!con) {
-- 
2.5.5

