qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/10] initial spice support
@ 2010-08-25 14:19 Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 01/10] Use display types for local display only Gerd Hoffmann
                   ` (9 more replies)
  0 siblings, 10 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

  Hi,

Here comes v3 of the iniial spice support patch series.
It brings just the very basic bits:

 * Detect spice in configure, Makefile windup.
 * Support for keyboard, mouse and tablet.
 * Support for simple display output (works as DisplayChangeListener,
   plays with any gfx card, sends simple draw commands to update
   dirty regions).

Note that this patch series does *not* yet contain the qxl paravirtual
gfx card.  That will come as part of a additional patch series after
sorting the vgabios support.

The patches are also available in the git repository at:
  git://anongit.freedesktop.org/spice/qemu submit.3

Changes since v2:
  * Add copyright headers to the files.
  * Add dprint for debug logging.
  * Add mapping for buttons and leds.
  * Add comments for locking+threads.
  * Drop includes which qemu-common.h brings in.
  * Compile -spice switch unconditionally.
  * Hook up spice init using module.h, drop #ifdefs.
  * Misc minor tweaks.

Gerd Hoffmann (10):
  Use display types for local display only.
  Use machine_init() to register virtfs config options.
  add pflib: PixelFormat conversion library.
  configure: add logging
  add spice into the configure file
  spice: core bits
  spice: add keyboard
  spice: add mouse
  spice: simple display
  spice: add tablet support

 Makefile.objs      |    3 +
 configure          |   42 +++++-
 fsdev/qemu-fsdev.c |    9 ++
 pflib.c            |  213 ++++++++++++++++++++++++++++
 pflib.h            |   20 +++
 qemu-config.c      |   18 +++
 qemu-config.h      |    1 +
 qemu-options.hx    |   21 +++
 sysemu.h           |    1 -
 ui/qemu-spice.h    |   41 ++++++
 ui/spice-core.c    |  178 +++++++++++++++++++++++
 ui/spice-display.c |  399 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 ui/spice-display.h |   69 +++++++++
 ui/spice-input.c   |  203 ++++++++++++++++++++++++++
 vl.c               |   49 +++++--
 15 files changed, 1248 insertions(+), 19 deletions(-)
 create mode 100644 pflib.c
 create mode 100644 pflib.h
 create mode 100644 ui/qemu-spice.h
 create mode 100644 ui/spice-core.c
 create mode 100644 ui/spice-display.c
 create mode 100644 ui/spice-display.h
 create mode 100644 ui/spice-input.c

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 01/10] Use display types for local display only.
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 02/10] Use machine_init() to register virtfs config options Gerd Hoffmann
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch drops DT_VNC.  The display types are only used to select
select the local display (i.e. curses, sdl, coca, ...).  Remote
displays (for now only vnc, spice will follow) can be enabled
independently.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 sysemu.h |    1 -
 vl.c     |   24 +++++++++++++-----------
 2 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/sysemu.h b/sysemu.h
index a1f6466..b81a70e 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -94,7 +94,6 @@ typedef enum DisplayType
     DT_DEFAULT,
     DT_CURSES,
     DT_SDL,
-    DT_VNC,
     DT_NOGRAPHIC,
 } DisplayType;
 
diff --git a/vl.c b/vl.c
index 91d1684..d90b275 100644
--- a/vl.c
+++ b/vl.c
@@ -172,6 +172,7 @@ static const char *data_dir;
 const char *bios_name = NULL;
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 DisplayType display_type = DT_DEFAULT;
+int display_remote = 0;
 const char* keyboard_layout = NULL;
 ram_addr_t ram_size;
 const char *mem_path = NULL;
@@ -2468,7 +2469,7 @@ int main(int argc, char **argv, char **envp)
                 }
                 break;
 	    case QEMU_OPTION_vnc:
-                display_type = DT_VNC;
+                display_remote++;
 		vnc_display = optarg;
 		break;
             case QEMU_OPTION_no_acpi:
@@ -2898,17 +2899,17 @@ int main(int argc, char **argv, char **envp)
     /* just use the first displaystate for the moment */
     ds = get_displaystate();
 
-    if (display_type == DT_DEFAULT) {
+    if (display_type == DT_DEFAULT && !display_remote) {
 #if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
         display_type = DT_SDL;
 #else
-        display_type = DT_VNC;
         vnc_display = "localhost:0,to=99";
         show_vnc_port = 1;
 #endif
     }
         
 
+    /* init local displays */
     switch (display_type) {
     case DT_NOGRAPHIC:
         break;
@@ -2926,7 +2927,12 @@ int main(int argc, char **argv, char **envp)
         cocoa_display_init(ds, full_screen);
         break;
 #endif
-    case DT_VNC:
+    default:
+        break;
+    }
+
+    /* init remote displays */
+    if (vnc_display) {
         vnc_display_init(ds);
         if (vnc_display_open(ds, vnc_display) < 0)
             exit(1);
@@ -2934,12 +2940,10 @@ int main(int argc, char **argv, char **envp)
         if (show_vnc_port) {
             printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
         }
-        break;
-    default:
-        break;
     }
-    dpy_resize(ds);
 
+    /* display setup */
+    dpy_resize(ds);
     dcl = ds->listeners;
     while (dcl != NULL) {
         if (dcl->dpy_refresh != NULL) {
@@ -2949,12 +2953,10 @@ int main(int argc, char **argv, char **envp)
         }
         dcl = dcl->next;
     }
-
-    if (display_type == DT_NOGRAPHIC || display_type == DT_VNC) {
+    if (ds->gui_timer == NULL) {
         nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL);
         qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
     }
-
     text_consoles_set_display(ds);
 
     if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 02/10] Use machine_init() to register virtfs config options.
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 01/10] Use display types for local display only Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 03/10] add pflib: PixelFormat conversion library Gerd Hoffmann
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann


Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 fsdev/qemu-fsdev.c |    9 +++++++++
 vl.c               |    5 -----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index ad69b0e..280b8f5 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -16,6 +16,7 @@
 #include "qemu-queue.h"
 #include "osdep.h"
 #include "qemu-common.h"
+#include "qemu-config.h"
 
 static QTAILQ_HEAD(FsTypeEntry_head, FsTypeListEntry) fstype_entries =
     QTAILQ_HEAD_INITIALIZER(fstype_entries);
@@ -75,3 +76,11 @@ FsTypeEntry *get_fsdev_fsentry(char *id)
     }
     return NULL;
 }
+
+static void fsdev_register_config(void)
+{
+    qemu_add_opts(&qemu_fsdev_opts);
+    qemu_add_opts(&qemu_virtfs_opts);
+}
+machine_init(fsdev_register_config);
+
diff --git a/vl.c b/vl.c
index d90b275..40bf30b 100644
--- a/vl.c
+++ b/vl.c
@@ -1856,11 +1856,6 @@ int main(int argc, char **argv, char **envp)
     tb_size = 0;
     autostart= 1;
 
-#ifdef CONFIG_VIRTFS
-    qemu_add_opts(&qemu_fsdev_opts);
-    qemu_add_opts(&qemu_virtfs_opts);
-#endif
-
     /* first pass of option parsing */
     optind = 1;
     while (optind < argc) {
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 03/10] add pflib: PixelFormat conversion library.
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 01/10] Use display types for local display only Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 02/10] Use machine_init() to register virtfs config options Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 04/10] configure: add logging Gerd Hoffmann
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann


Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.objs |    1 +
 pflib.c       |  213 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 pflib.h       |   20 ++++++
 3 files changed, 234 insertions(+), 0 deletions(-)
 create mode 100644 pflib.c
 create mode 100644 pflib.h

diff --git a/Makefile.objs b/Makefile.objs
index 4a1eaa1..edfca87 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -83,6 +83,7 @@ common-obj-y += qemu-char.o savevm.o #aio.o
 common-obj-y += msmouse.o ps2.o
 common-obj-y += qdev.o qdev-properties.o
 common-obj-y += block-migration.o
+common-obj-y += pflib.o
 
 common-obj-$(CONFIG_BRLAPI) += baum.o
 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
diff --git a/pflib.c b/pflib.c
new file mode 100644
index 0000000..1154d0c
--- /dev/null
+++ b/pflib.c
@@ -0,0 +1,213 @@
+/*
+ * PixelFormat conversion library.
+ *
+ * Author: Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include "qemu-common.h"
+#include "console.h"
+#include "pflib.h"
+
+typedef struct QemuPixel QemuPixel;
+
+typedef void (*pf_convert)(QemuPfConv *conv,
+                           void *dst, void *src, uint32_t cnt);
+typedef void (*pf_convert_from)(PixelFormat *pf,
+                                QemuPixel *dst, void *src, uint32_t cnt);
+typedef void (*pf_convert_to)(PixelFormat *pf,
+                              void *dst, QemuPixel *src, uint32_t cnt);
+
+struct QemuPfConv {
+    pf_convert        convert;
+    PixelFormat       src;
+    PixelFormat       dst;
+
+    /* for copy_generic() */
+    pf_convert_from   conv_from;
+    pf_convert_to     conv_to;
+    QemuPixel         *conv_buf;
+    uint32_t          conv_cnt;
+};
+
+struct QemuPixel {
+    uint8_t red;
+    uint8_t green;
+    uint8_t blue;
+    uint8_t alpha;
+};
+
+/* ----------------------------------------------------------------------- */
+/* PixelFormat -> QemuPixel conversions                                    */
+
+static void conv_16_to_pixel(PixelFormat *pf,
+                             QemuPixel *dst, void *src, uint32_t cnt)
+{
+    uint16_t *src16 = src;
+
+    while (cnt > 0) {
+        dst->red   = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
+        dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
+        dst->blue  = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
+        dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits);
+        dst++, src16++, cnt--;
+    }
+}
+
+/* assumes pf->{r,g,b,a}bits == 8 */
+static void conv_32_to_pixel_fast(PixelFormat *pf,
+                                  QemuPixel *dst, void *src, uint32_t cnt)
+{
+    uint32_t *src32 = src;
+
+    while (cnt > 0) {
+        dst->red   = (*src32 & pf->rmask) >> pf->rshift;
+        dst->green = (*src32 & pf->gmask) >> pf->gshift;
+        dst->blue  = (*src32 & pf->bmask) >> pf->bshift;
+        dst->alpha = (*src32 & pf->amask) >> pf->ashift;
+        dst++, src32++, cnt--;
+    }
+}
+
+static void conv_32_to_pixel_generic(PixelFormat *pf,
+                                     QemuPixel *dst, void *src, uint32_t cnt)
+{
+    uint32_t *src32 = src;
+
+    while (cnt > 0) {
+        if (pf->rbits < 8) {
+            dst->red   = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits);
+        } else {
+            dst->red   = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8);
+        }
+        if (pf->gbits < 8) {
+            dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits);
+        } else {
+            dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8);
+        }
+        if (pf->bbits < 8) {
+            dst->blue  = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits);
+        } else {
+            dst->blue  = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8);
+        }
+        if (pf->abits < 8) {
+            dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits);
+        } else {
+            dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8);
+        }
+        dst++, src32++, cnt--;
+    }
+}
+
+/* ----------------------------------------------------------------------- */
+/* QemuPixel -> PixelFormat conversions                                    */
+
+static void conv_pixel_to_16(PixelFormat *pf,
+                             void *dst, QemuPixel *src, uint32_t cnt)
+{
+    uint16_t *dst16 = dst;
+
+    while (cnt > 0) {
+        *dst16  = ((uint16_t)src->red   >> (8 - pf->rbits)) << pf->rshift;
+        *dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift;
+        *dst16 |= ((uint16_t)src->blue  >> (8 - pf->bbits)) << pf->bshift;
+        *dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
+        dst16++, src++, cnt--;
+    }
+}
+
+static void conv_pixel_to_32(PixelFormat *pf,
+                             void *dst, QemuPixel *src, uint32_t cnt)
+{
+    uint32_t *dst32 = dst;
+
+    while (cnt > 0) {
+        *dst32  = ((uint32_t)src->red   >> (8 - pf->rbits)) << pf->rshift;
+        *dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift;
+        *dst32 |= ((uint32_t)src->blue  >> (8 - pf->bbits)) << pf->bshift;
+        *dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift;
+        dst32++, src++, cnt--;
+    }
+}
+
+/* ----------------------------------------------------------------------- */
+/* PixelFormat -> PixelFormat conversions                                  */
+
+static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
+{
+    uint32_t bytes = cnt * conv->src.bytes_per_pixel;
+    memcpy(dst, src, bytes);
+}
+
+static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
+{
+    if (conv->conv_cnt < cnt) {
+        conv->conv_cnt = cnt;
+        conv->conv_buf = qemu_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt);
+    }
+    conv->conv_from(&conv->src, conv->conv_buf, src, cnt);
+    conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt);
+}
+
+/* ----------------------------------------------------------------------- */
+/* public interface                                                        */
+
+QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src)
+{
+    QemuPfConv *conv = qemu_mallocz(sizeof(QemuPfConv));
+
+    conv->src = *src;
+    conv->dst = *dst;
+
+    if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) {
+        /* formats identical, can simply copy */
+        conv->convert = convert_copy;
+    } else {
+        /* generic two-step conversion: src -> QemuPixel -> dst  */
+        switch (conv->src.bytes_per_pixel) {
+        case 2:
+            conv->conv_from = conv_16_to_pixel;
+            break;
+        case 4:
+            if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) {
+                conv->conv_from = conv_32_to_pixel_fast;
+            } else {
+                conv->conv_from = conv_32_to_pixel_generic;
+            }
+            break;
+        default:
+            goto err;
+        }
+        switch (conv->dst.bytes_per_pixel) {
+        case 2:
+            conv->conv_to = conv_pixel_to_16;
+            break;
+        case 4:
+            conv->conv_to = conv_pixel_to_32;
+            break;
+        default:
+            goto err;
+        }
+        conv->convert = convert_generic;
+    }
+    return conv;
+
+err:
+    qemu_free(conv);
+    return NULL;
+}
+
+void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt)
+{
+    conv->convert(conv, dst, src, cnt);
+}
+
+void qemu_pf_conv_put(QemuPfConv *conv)
+{
+    if (conv) {
+        qemu_free(conv->conv_buf);
+        qemu_free(conv);
+    }
+}
diff --git a/pflib.h b/pflib.h
new file mode 100644
index 0000000..b70c313
--- /dev/null
+++ b/pflib.h
@@ -0,0 +1,20 @@
+#ifndef __QEMU_PFLIB_H
+#define __QEMU_PFLIB_H
+
+/*
+ * PixelFormat conversion library.
+ *
+ * Author: Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+typedef struct QemuPfConv QemuPfConv;
+
+QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src);
+void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt);
+void qemu_pf_conv_put(QemuPfConv *conv);
+
+#endif
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 04/10] configure: add logging
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 03/10] add pflib: PixelFormat conversion library Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 05/10] add spice into the configure file Gerd Hoffmann
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Write compile commands and messages to config.log.
Useful for debugging configure.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 configure |    7 +++++--
 1 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/configure b/configure
index a20371c..13d8be0 100755
--- a/configure
+++ b/configure
@@ -16,15 +16,18 @@ TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
 TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
 
 trap "rm -f $TMPC $TMPO $TMPE ; exit" EXIT INT QUIT TERM
+rm -f config.log
 
 compile_object() {
-  $cc $QEMU_CFLAGS -c -o $TMPO $TMPC > /dev/null 2> /dev/null
+  echo $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log
+  $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log 2>&1
 }
 
 compile_prog() {
   local_cflags="$1"
   local_ldflags="$2"
-  $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags > /dev/null 2> /dev/null
+  echo $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log
+  $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1
 }
 
 # check whether a command is available to this shell (may be either an
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 05/10] add spice into the configure file
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 04/10] configure: add logging Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 06/10] spice: core bits Gerd Hoffmann
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann


Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 configure |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/configure b/configure
index 13d8be0..0998e86 100755
--- a/configure
+++ b/configure
@@ -318,6 +318,7 @@ pkgversion=""
 check_utests="no"
 user_pie="no"
 zero_malloc=""
+spice=""
 
 # OS specific
 if check_define __linux__ ; then
@@ -619,6 +620,10 @@ for opt do
   ;;
   --enable-kvm) kvm="yes"
   ;;
+  --disable-spice) spice="no"
+  ;;
+  --enable-spice) spice="yes"
+  ;;
   --enable-profiler) profiler="yes"
   ;;
   --enable-cocoa)
@@ -898,6 +903,8 @@ echo "  --enable-docs            enable documentation build"
 echo "  --disable-docs           disable documentation build"
 echo "  --disable-vhost-net      disable vhost-net acceleration support"
 echo "  --enable-vhost-net       enable vhost-net acceleration support"
+echo "  --disable-spice          disable spice"
+echo "  --enable-spice           enable spice"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -2048,6 +2055,29 @@ if compile_prog "" ""; then
     gcc_attribute_warn_unused_result=yes
 fi
 
+# spice probe
+if test "$spice" != "no" ; then
+  cat > $TMPC << EOF
+#include <spice.h>
+int main(void) { spice_server_new(); return 0; }
+EOF
+  spice_cflags=$($pkgconfig --cflags spice-protocol spice-server 2>/dev/null)
+  spice_libs=$($pkgconfig --libs spice-protocol spice-server 2>/dev/null)
+  if $pkgconfig --atleast-version=0.5.3 spice-server &&\
+     compile_prog "$spice_cflags" "$spice_libs" ; then
+    spice="yes"
+    libs_softmmu="$libs_softmmu $spice_libs"
+    QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags"
+  else
+    if test "$spice" = "yes" ; then
+      feature_not_found "spice"
+    fi
+    spice="no"
+  fi
+fi
+
+##########################################
+
 ##########################################
 # check if we have fdatasync
 
@@ -2190,6 +2220,7 @@ echo "preadv support    $preadv"
 echo "fdatasync         $fdatasync"
 echo "uuid support      $uuid"
 echo "vhost-net support $vhost_net"
+echo "spice support     $spice"
 
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -2427,6 +2458,10 @@ if test "$fdatasync" = "yes" ; then
   echo "CONFIG_FDATASYNC=y" >> $config_host_mak
 fi
 
+if test "$spice" = "yes" ; then
+  echo "CONFIG_SPICE=y" >> $config_host_mak
+fi
+
 # XXX: suppress that
 if [ "$bsd" = "yes" ] ; then
   echo "CONFIG_BSD=y" >> $config_host_mak
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 06/10] spice: core bits
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 05/10] add spice into the configure file Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 07/10] spice: add keyboard Gerd Hoffmann
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add -spice command line switch.  Has support setting passwd and port for
now.  With this patch applied the spice client can successfully connect
to qemu.  You can't do anything useful yet though.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.objs   |    2 +
 qemu-config.c   |   18 ++++++
 qemu-config.h   |    1 +
 qemu-options.hx |   21 +++++++
 ui/qemu-spice.h |   39 ++++++++++++
 ui/spice-core.c |  176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 vl.c            |   15 +++++
 7 files changed, 272 insertions(+), 0 deletions(-)
 create mode 100644 ui/qemu-spice.h
 create mode 100644 ui/spice-core.c

diff --git a/Makefile.objs b/Makefile.objs
index edfca87..1a53027 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -88,6 +88,8 @@ common-obj-y += pflib.o
 common-obj-$(CONFIG_BRLAPI) += baum.o
 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
 
+common-obj-$(CONFIG_SPICE) += ui/spice-core.o
+
 audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 audio-obj-$(CONFIG_SDL) += sdlaudio.o
 audio-obj-$(CONFIG_OSS) += ossaudio.o
diff --git a/qemu-config.c b/qemu-config.c
index 3abe655..4c47cd0 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -336,6 +336,24 @@ static QemuOptsList qemu_cpudef_opts = {
     },
 };
 
+QemuOptsList qemu_spice_opts = {
+    .name = "spice",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
+    .desc = {
+        {
+            .name = "port",
+            .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "password",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "disable-ticketing",
+            .type = QEMU_OPT_BOOL,
+        },
+        { /* end if list */ }
+    },
+};
+
 static QemuOptsList *vm_config_groups[32] = {
     &qemu_drive_opts,
     &qemu_chardev_opts,
diff --git a/qemu-config.h b/qemu-config.h
index 533a049..20d707f 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -3,6 +3,7 @@
 
 extern QemuOptsList qemu_fsdev_opts;
 extern QemuOptsList qemu_virtfs_opts;
+extern QemuOptsList qemu_spice_opts;
 
 QemuOptsList *qemu_find_opts(const char *group);
 void qemu_add_opts(QemuOptsList *list);
diff --git a/qemu-options.hx b/qemu-options.hx
index 453f129..87bd451 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -670,6 +670,27 @@ STEXI
 Enable SDL.
 ETEXI
 
+DEF("spice", HAS_ARG, QEMU_OPTION_spice,
+    "-spice <args>   enable spice\n", QEMU_ARCH_ALL)
+STEXI
+@item -spice @var{option}[,@var{option}[,...]]
+@findex -spice
+Enable the spice remote desktop protocol. Valid options are
+
+@table @option
+
+@item port=<nr>
+Set the TCP port spice is listening on.
+
+@item password=<secret>
+Set the password you need to authenticate.
+
+@item disable-ticketing
+Allow client connects without authentication.
+
+@end table
+ETEXI
+
 DEF("portrait", 0, QEMU_OPTION_portrait,
     "-portrait       rotate graphical output 90 deg left (only PXA LCD)\n",
     QEMU_ARCH_ALL)
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
new file mode 100644
index 0000000..d58d74c
--- /dev/null
+++ b/ui/qemu-spice.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_SPICE_H
+#define QEMU_SPICE_H
+
+#ifdef CONFIG_SPICE
+
+#include <spice.h>
+
+#include "qemu-option.h"
+#include "qemu-config.h"
+
+extern SpiceServer *spice_server;
+extern int using_spice;
+
+void qemu_spice_init(void);
+
+#else  /* CONFIG_SPICE */
+
+#define using_spice 0
+
+#endif /* CONFIG_SPICE */
+
+#endif /* QEMU_SPICE_H */
diff --git a/ui/spice-core.c b/ui/spice-core.c
new file mode 100644
index 0000000..3041309
--- /dev/null
+++ b/ui/spice-core.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <spice.h>
+#include <spice-experimental.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "qemu-timer.h"
+#include "qemu-queue.h"
+#include "monitor.h"
+
+/* core bits */
+
+SpiceServer *spice_server;
+int using_spice = 0;
+
+struct SpiceTimer {
+    QEMUTimer *timer;
+    QTAILQ_ENTRY(SpiceTimer) next;
+};
+static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers);
+
+static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque)
+{
+    SpiceTimer *timer;
+
+    timer = qemu_mallocz(sizeof(*timer));
+    timer->timer = qemu_new_timer(rt_clock, func, opaque);
+    QTAILQ_INSERT_TAIL(&timers, timer, next);
+    return timer;
+}
+
+static void timer_start(SpiceTimer *timer, uint32_t ms)
+{
+    qemu_mod_timer(timer->timer, qemu_get_clock(rt_clock) + ms);
+}
+
+static void timer_cancel(SpiceTimer *timer)
+{
+    qemu_del_timer(timer->timer);
+}
+
+static void timer_remove(SpiceTimer *timer)
+{
+    qemu_del_timer(timer->timer);
+    qemu_free_timer(timer->timer);
+    QTAILQ_REMOVE(&timers, timer, next);
+    qemu_free(timer);
+}
+
+struct SpiceWatch {
+    int fd;
+    int event_mask;
+    SpiceWatchFunc func;
+    void *opaque;
+    QTAILQ_ENTRY(SpiceWatch) next;
+};
+static QTAILQ_HEAD(, SpiceWatch) watches = QTAILQ_HEAD_INITIALIZER(watches);
+
+static void watch_read(void *opaque)
+{
+    SpiceWatch *watch = opaque;
+    watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque);
+}
+
+static void watch_write(void *opaque)
+{
+    SpiceWatch *watch = opaque;
+    watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque);
+}
+
+static void watch_update_mask(SpiceWatch *watch, int event_mask)
+{
+    IOHandler *on_read = NULL;
+    IOHandler *on_write = NULL;
+
+    watch->event_mask = event_mask;
+    if (watch->event_mask & SPICE_WATCH_EVENT_READ)
+        on_read = watch_read;
+    if (watch->event_mask & SPICE_WATCH_EVENT_WRITE)
+        on_read = watch_write;
+    qemu_set_fd_handler(watch->fd, on_read, on_write, watch);
+}
+
+static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
+{
+    SpiceWatch *watch;
+
+    watch = qemu_mallocz(sizeof(*watch));
+    watch->fd     = fd;
+    watch->func   = func;
+    watch->opaque = opaque;
+    QTAILQ_INSERT_TAIL(&watches, watch, next);
+
+    watch_update_mask(watch, event_mask);
+    return watch;
+}
+
+static void watch_remove(SpiceWatch *watch)
+{
+    watch_update_mask(watch, 0);
+    QTAILQ_REMOVE(&watches, watch, next);
+    qemu_free(watch);
+}
+
+static SpiceCoreInterface core_interface = {
+    .base.type          = SPICE_INTERFACE_CORE,
+    .base.description   = "qemu core services",
+    .base.major_version = SPICE_INTERFACE_CORE_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_CORE_MINOR,
+
+    .timer_add          = timer_add,
+    .timer_start        = timer_start,
+    .timer_cancel       = timer_cancel,
+    .timer_remove       = timer_remove,
+
+    .watch_add          = watch_add,
+    .watch_update_mask  = watch_update_mask,
+    .watch_remove       = watch_remove,
+};
+
+/* functions for the rest of qemu */
+
+void qemu_spice_init(void)
+{
+    QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
+    const char *password;
+    int port;
+
+    if (!opts)
+        return;
+    port = qemu_opt_get_number(opts, "port", 0);
+    if (!port)
+        return;
+    password = qemu_opt_get(opts, "password");
+
+    spice_server = spice_server_new();
+    spice_server_set_port(spice_server, port);
+    if (password)
+        spice_server_set_ticket(spice_server, password, 0, 0, 0);
+    if (qemu_opt_get_bool(opts, "disable-ticketing", 0))
+        spice_server_set_noauth(spice_server);
+
+    /* TODO: make configurable via cmdline */
+    spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ);
+
+    spice_server_init(spice_server, &core_interface);
+    using_spice = 1;
+}
+
+static void spice_register_config(void)
+{
+    qemu_add_opts(&qemu_spice_opts);
+}
+machine_init(spice_register_config);
+
+static void spice_initialize(void)
+{
+    qemu_spice_init();
+}
+device_init(spice_initialize);
diff --git a/vl.c b/vl.c
index 40bf30b..a8c2a33 100644
--- a/vl.c
+++ b/vl.c
@@ -161,6 +161,8 @@ int main(int argc, char **argv)
 #include "cpus.h"
 #include "arch_init.h"
 
+#include "ui/qemu-spice.h"
+
 //#define DEBUG_NET
 //#define DEBUG_SLIRP
 
@@ -2599,6 +2601,19 @@ int main(int argc, char **argv, char **envp)
                     }
                     break;
                 }
+            case QEMU_OPTION_spice:
+                olist = qemu_find_opts("spice");
+                if (!olist) {
+                    fprintf(stderr, "spice is not supported by this qemu build.\n");
+                    exit(1);
+                }
+                opts = qemu_opts_parse(olist, optarg, 0);
+                if (!opts) {
+                    fprintf(stderr, "parse error: %s\n", optarg);
+                    exit(1);
+                }
+                display_remote++;
+                break;
             case QEMU_OPTION_writeconfig:
                 {
                     FILE *fp;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 07/10] spice: add keyboard
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 06/10] spice: core bits Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  2010-08-25 19:53   ` Anthony Liguori
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 08/10] spice: add mouse Gerd Hoffmann
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Open keyboard channel.  Now you can type into the spice client and the
keyboard events are sent to your guest.  You'll need some other display
like vnc to actually see the guest responding to them though.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.objs    |    2 +-
 ui/qemu-spice.h  |    1 +
 ui/spice-core.c  |    2 +
 ui/spice-input.c |   82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 86 insertions(+), 1 deletions(-)
 create mode 100644 ui/spice-input.c

diff --git a/Makefile.objs b/Makefile.objs
index 1a53027..20e6ad7 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -88,7 +88,7 @@ common-obj-y += pflib.o
 common-obj-$(CONFIG_BRLAPI) += baum.o
 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
 
-common-obj-$(CONFIG_SPICE) += ui/spice-core.o
+common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o
 
 audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 audio-obj-$(CONFIG_SDL) += sdlaudio.o
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index d58d74c..75e2502 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -29,6 +29,7 @@ extern SpiceServer *spice_server;
 extern int using_spice;
 
 void qemu_spice_init(void);
+void qemu_spice_input_init(void);
 
 #else  /* CONFIG_SPICE */
 
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 3041309..75f0fe9 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -161,6 +161,8 @@ void qemu_spice_init(void)
 
     spice_server_init(spice_server, &core_interface);
     using_spice = 1;
+
+    qemu_spice_input_init();
 }
 
 static void spice_register_config(void)
diff --git a/ui/spice-input.c b/ui/spice-input.c
new file mode 100644
index 0000000..d4f44f4
--- /dev/null
+++ b/ui/spice-input.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <spice.h>
+#include <spice/enums.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "console.h"
+
+/* keyboard bits */
+
+typedef struct QemuSpiceKbd {
+    SpiceKbdInstance sin;
+    int ledstate;
+} QemuSpiceKbd;
+
+static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
+static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
+static void kbd_leds(void *opaque, int l);
+
+static const SpiceKbdInterface kbd_interface = {
+    .base.type          = SPICE_INTERFACE_KEYBOARD,
+    .base.description   = "qemu keyboard",
+    .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
+    .push_scan_freg     = kbd_push_key,
+    .get_leds           = kbd_get_leds,
+};
+
+static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
+{
+    kbd_put_keycode(frag);
+}
+
+static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
+{
+    QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
+    return kbd->ledstate;
+}
+
+static void kbd_leds(void *opaque, int ledstate)
+{
+    QemuSpiceKbd *kbd = opaque;
+
+    kbd->ledstate = 0;
+    if (ledstate & QEMU_SCROLL_LOCK_LED)
+        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK;
+    if (ledstate & QEMU_NUM_LOCK_LED)
+        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK;
+    if (ledstate & QEMU_CAPS_LOCK_LED)
+        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK;
+    spice_server_kbd_leds(&kbd->sin, ledstate);
+}
+
+void qemu_spice_input_init(void)
+{
+    QemuSpiceKbd *kbd;
+
+    kbd = qemu_mallocz(sizeof(*kbd));
+    kbd->sin.base.sif = &kbd_interface.base;
+    spice_server_add_interface(spice_server, &kbd->sin.base);
+    qemu_add_led_event_handler(kbd_leds, kbd);
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 08/10] spice: add mouse
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
                   ` (6 preceding siblings ...)
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 07/10] spice: add keyboard Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 09/10] spice: simple display Gerd Hoffmann
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 10/10] spice: add tablet support Gerd Hoffmann
  9 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Open mouse channel.  Now you can move the guests mouse pointer.
No tablet / absolute positioning (yet) though.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 ui/spice-input.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/ui/spice-input.c b/ui/spice-input.c
index d4f44f4..130760d 100644
--- a/ui/spice-input.c
+++ b/ui/spice-input.c
@@ -71,12 +71,56 @@ static void kbd_leds(void *opaque, int ledstate)
     spice_server_kbd_leds(&kbd->sin, ledstate);
 }
 
+/* mouse bits */
+
+typedef struct QemuSpiceMouse {
+    SpiceMouseInstance sin;
+} QemuSpiceMouse;
+
+static int map_buttons(int spice_buttons)
+{
+    int qemu_buttons = 0;
+
+    if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_LEFT)
+        qemu_buttons |= MOUSE_EVENT_LBUTTON;
+    if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_MIDDLE)
+        qemu_buttons |= MOUSE_EVENT_MBUTTON;
+    if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_RIGHT)
+        qemu_buttons |= MOUSE_EVENT_RBUTTON;
+    return qemu_buttons;
+}
+
+static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
+                         uint32_t buttons_state)
+{
+    kbd_mouse_event(dx, dy, dz, map_buttons(buttons_state));
+}
+
+static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
+{
+    kbd_mouse_event(0, 0, 0, map_buttons(buttons_state));
+}
+
+static const SpiceMouseInterface mouse_interface = {
+    .base.type          = SPICE_INTERFACE_MOUSE,
+    .base.description   = "mouse",
+    .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR,
+    .motion             = mouse_motion,
+    .buttons            = mouse_buttons,
+};
+
 void qemu_spice_input_init(void)
 {
     QemuSpiceKbd *kbd;
+    QemuSpiceMouse *mouse;
 
     kbd = qemu_mallocz(sizeof(*kbd));
     kbd->sin.base.sif = &kbd_interface.base;
     spice_server_add_interface(spice_server, &kbd->sin.base);
     qemu_add_led_event_handler(kbd_leds, kbd);
+
+    mouse = qemu_mallocz(sizeof(*mouse));
+    mouse->sin.base.sif = &mouse_interface.base;
+    spice_server_add_interface(spice_server, &mouse->sin.base);
 }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 09/10] spice: simple display
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
                   ` (7 preceding siblings ...)
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 08/10] spice: add mouse Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  2010-08-25 19:57   ` Anthony Liguori
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 10/10] spice: add tablet support Gerd Hoffmann
  9 siblings, 1 reply; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

With that patch applied you'll actually see the guests screen in the
spice client.  This does *not* bring qxl and full spice support though.
This is basically the qxl vga mode made more generic, so it plays
together with any qemu-emulated gfx card.  You can display stdvga or
cirrus via spice client.  You can have both vnc and spice enabled and
clients connected at the same time.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile.objs      |    2 +-
 ui/qemu-spice.h    |    1 +
 ui/spice-display.c |  399 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 ui/spice-display.h |   69 +++++++++
 vl.c               |    5 +
 5 files changed, 475 insertions(+), 1 deletions(-)
 create mode 100644 ui/spice-display.c
 create mode 100644 ui/spice-display.h

diff --git a/Makefile.objs b/Makefile.objs
index 20e6ad7..d09a1e4 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -88,7 +88,7 @@ common-obj-y += pflib.o
 common-obj-$(CONFIG_BRLAPI) += baum.o
 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
 
-common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o
+common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o
 
 audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
 audio-obj-$(CONFIG_SDL) += sdlaudio.o
diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
index 75e2502..5d6e2ea 100644
--- a/ui/qemu-spice.h
+++ b/ui/qemu-spice.h
@@ -30,6 +30,7 @@ extern int using_spice;
 
 void qemu_spice_init(void);
 void qemu_spice_input_init(void);
+void qemu_spice_display_init(DisplayState *ds);
 
 #else  /* CONFIG_SPICE */
 
diff --git a/ui/spice-display.c b/ui/spice-display.c
new file mode 100644
index 0000000..7163714
--- /dev/null
+++ b/ui/spice-display.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+
+#include "qemu-common.h"
+#include "qemu-spice.h"
+#include "qemu-timer.h"
+#include "qemu-queue.h"
+#include "monitor.h"
+#include "console.h"
+#include "sysemu.h"
+
+#include "spice-display.h"
+
+static int debug = 0;
+
+static void __attribute__((format(printf,2,3)))
+dprint(int level, const char *fmt, ...)
+{
+    va_list args;
+
+    if (level <= debug) {
+        va_start(args, fmt);
+        vfprintf(stderr, fmt, args);
+        va_end(args);
+    }
+}
+
+int qemu_spice_rect_is_empty(const QXLRect* r)
+{
+    return r->top == r->bottom || r->left == r->right;
+}
+
+void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
+{
+    if (qemu_spice_rect_is_empty(r)) {
+        return;
+    }
+
+    if (qemu_spice_rect_is_empty(dest)) {
+        *dest = *r;
+        return;
+    }
+
+    dest->top = MIN(dest->top, r->top);
+    dest->left = MIN(dest->left, r->left);
+    dest->bottom = MAX(dest->bottom, r->bottom);
+    dest->right = MAX(dest->right, r->right);
+}
+
+/* called from spice server thread context (via interface_get_command) */
+SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+{
+    SimpleSpiceUpdate *update;
+    QXLDrawable *drawable;
+    QXLImage *image;
+    QXLCommand *cmd;
+    uint8_t *src, *dst;
+    int by, bw, bh;
+
+    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+        return NULL;
+    };
+
+    pthread_mutex_lock(&ssd->lock);
+    dprint(2, "%s: lr %d -> %d,  tb -> %d -> %d\n", __FUNCTION__,
+           ssd->dirty.left, ssd->dirty.right,
+           ssd->dirty.top, ssd->dirty.bottom);
+
+    update   = qemu_mallocz(sizeof(*update));
+    drawable = &update->drawable;
+    image    = &update->image;
+    cmd      = &update->ext.cmd;
+
+    bw       = ssd->dirty.right - ssd->dirty.left;
+    bh       = ssd->dirty.bottom - ssd->dirty.top;
+    update->bitmap = qemu_malloc(bw * bh * 4);
+
+    drawable->bbox            = ssd->dirty;
+    drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
+    drawable->effect          = QXL_EFFECT_OPAQUE;
+    drawable->release_info.id = (intptr_t)update;
+    drawable->type            = QXL_DRAW_COPY;
+
+    drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
+    drawable->u.copy.src_bitmap      = (intptr_t)image;
+    drawable->u.copy.src_area.right  = bw;
+    drawable->u.copy.src_area.bottom = bh;
+
+    QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++);
+    image->descriptor.type   = SPICE_IMAGE_TYPE_BITMAP;
+    image->bitmap.flags      = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
+    image->bitmap.stride     = bw * 4;
+    image->descriptor.width  = image->bitmap.x = bw;
+    image->descriptor.height = image->bitmap.y = bh;
+    image->bitmap.data = (intptr_t)(update->bitmap);
+    image->bitmap.palette = 0;
+    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
+
+    if (ssd->conv == NULL) {
+        PixelFormat dst = qemu_default_pixelformat(32);
+        ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf);
+        assert(ssd->conv);
+    }
+
+    src = ds_get_data(ssd->ds) +
+        ssd->dirty.top * ds_get_linesize(ssd->ds) +
+        ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds);
+    dst = update->bitmap;
+    for (by = 0; by < bh; by++) {
+        qemu_pf_conv_run(ssd->conv, dst, src, bw);
+        src += ds_get_linesize(ssd->ds);
+        dst += image->bitmap.stride;
+    }
+
+    cmd->type = QXL_CMD_DRAW;
+    cmd->data = (intptr_t)drawable;
+
+    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
+    pthread_mutex_unlock(&ssd->lock);
+    return update;
+}
+
+/* called from spice server thread context (via interface_release_ressource) */
+void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
+{
+    qemu_free(update->bitmap);
+    qemu_free(update);
+}
+
+void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
+{
+    QXLDevMemSlot memslot;
+
+    dprint(1, "%s:\n", __FUNCTION__);
+
+    memset(&memslot, 0, sizeof(memslot));
+    memslot.slot_group_id = MEMSLOT_GROUP_HOST;
+    memslot.virt_end = ~0;
+    ssd->worker->add_memslot(ssd->worker, &memslot);
+}
+
+void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+{
+    QXLDevSurfaceCreate surface;
+
+    dprint(1, "%s: %dx%d\n", __FUNCTION__,
+           ds_get_width(ssd->ds), ds_get_height(ssd->ds));
+
+    surface.format     = SPICE_SURFACE_FMT_32_xRGB;
+    surface.width      = ds_get_width(ssd->ds);
+    surface.height     = ds_get_height(ssd->ds);
+    surface.stride     = -surface.width * 4;
+    surface.mouse_mode = 0;
+    surface.flags      = 0;
+    surface.type       = 0;
+    surface.mem        = (intptr_t)ssd->buf;
+    surface.group_id   = MEMSLOT_GROUP_HOST;
+    ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
+}
+
+void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+
+    ssd->worker->destroy_primary_surface(ssd->worker, 0);
+}
+
+void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+{
+    SimpleSpiceDisplay *ssd = opaque;
+
+    if (running) {
+        ssd->worker->start(ssd->worker);
+    } else {
+        ssd->worker->stop(ssd->worker);
+    }
+    ssd->running = running;
+}
+
+/* display listener callbacks */
+
+void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+                               int x, int y, int w, int h)
+{
+    QXLRect update_area;
+
+    dprint(2, "%s: x %d y %d w %d h %d\n", __FUNCTION__, x, y, w, h);
+    update_area.left = x,
+    update_area.right = x + w;
+    update_area.top = y;
+    update_area.bottom = y + h;
+
+    pthread_mutex_lock(&ssd->lock);
+    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+        ssd->notify++;
+    }
+    qemu_spice_rect_union(&ssd->dirty, &update_area);
+    pthread_mutex_unlock(&ssd->lock);
+}
+
+void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+
+    pthread_mutex_lock(&ssd->lock);
+    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
+    qemu_pf_conv_put(ssd->conv);
+    ssd->conv = NULL;
+    pthread_mutex_unlock(&ssd->lock);
+
+    qemu_spice_destroy_host_primary(ssd);
+    qemu_spice_create_host_primary(ssd);
+
+    pthread_mutex_lock(&ssd->lock);
+    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
+    ssd->notify++;
+    pthread_mutex_unlock(&ssd->lock);
+}
+
+void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
+{
+    dprint(3, "%s:\n", __FUNCTION__);
+    vga_hw_update();
+    if (ssd->notify) {
+        ssd->notify = 0;
+        ssd->worker->wakeup(ssd->worker);
+        if (debug > 1)
+            fprintf(stderr, "%s: notify\n", __FUNCTION__);
+    }
+}
+
+/* spice display interface callbacks */
+
+static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
+{
+    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+
+    dprint(1, "%s:\n", __FUNCTION__);
+    ssd->worker = qxl_worker;
+}
+
+static void interface_set_compression_level(QXLInstance *sin, int level)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+    /* nothing to do */
+}
+
+static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
+{
+    dprint(3, "%s:\n", __FUNCTION__);
+    /* nothing to do */
+}
+
+static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+{
+    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+
+    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
+    info->memslot_id_bits  = MEMSLOT_SLOT_BITS;
+    info->num_memslots = NUM_MEMSLOTS;
+    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
+    info->internal_groupslot_id = 0;
+    info->qxl_ram_size = ssd->bufsize;
+    info->n_surfaces = NUM_SURFACES;
+}
+
+static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+    SimpleSpiceUpdate *update;
+
+    dprint(3, "%s:\n", __FUNCTION__);
+    update = qemu_spice_create_update(ssd);
+    if (update == NULL) {
+        return false;
+    }
+    *ext = update->ext;
+    return true;
+}
+
+static int interface_req_cmd_notification(QXLInstance *sin)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+    return 1;
+}
+
+static void interface_release_resource(QXLInstance *sin,
+                                       struct QXLReleaseInfoExt ext)
+{
+    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+    uintptr_t id;
+
+    dprint(2, "%s:\n", __FUNCTION__);
+    id = ext.info->id;
+    qemu_spice_destroy_update(ssd, (void*)id);
+}
+
+static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    dprint(3, "%s:\n", __FUNCTION__);
+    return false;
+}
+
+static int interface_req_cursor_notification(QXLInstance *sin)
+{
+    dprint(1, "%s:\n", __FUNCTION__);
+    return 1;
+}
+
+static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
+{
+    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
+    abort();
+}
+
+static int interface_flush_resources(QXLInstance *sin)
+{
+    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
+    abort();
+    return 0;
+}
+
+static const QXLInterface dpy_interface = {
+    .base.type               = SPICE_INTERFACE_QXL,
+    .base.description        = "qemu simple display",
+    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
+    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
+
+    .attache_worker          = interface_attach_worker,
+    .set_compression_level   = interface_set_compression_level,
+    .set_mm_time             = interface_set_mm_time,
+    .get_init_info           = interface_get_init_info,
+
+    /* the callbacks below are called from spice server thread context */
+    .get_command             = interface_get_command,
+    .req_cmd_notification    = interface_req_cmd_notification,
+    .release_resource        = interface_release_resource,
+    .get_cursor_command      = interface_get_cursor_command,
+    .req_cursor_notification = interface_req_cursor_notification,
+    .notify_update           = interface_notify_update,
+    .flush_resources         = interface_flush_resources,
+};
+
+static SimpleSpiceDisplay sdpy;
+
+static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
+{
+    qemu_spice_display_update(&sdpy, x, y, w, h);
+}
+
+static void display_resize(struct DisplayState *ds)
+{
+    qemu_spice_display_resize(&sdpy);
+}
+
+static void display_refresh(struct DisplayState *ds)
+{
+    qemu_spice_display_refresh(&sdpy);
+}
+
+static DisplayChangeListener display_listener = {
+    .dpy_update  = display_update,
+    .dpy_resize  = display_resize,
+    .dpy_refresh = display_refresh,
+};
+
+void qemu_spice_display_init(DisplayState *ds)
+{
+    assert(sdpy.ds == NULL);
+    sdpy.ds = ds;
+    sdpy.bufsize = (16 * 1024 * 1024);
+    sdpy.buf = qemu_malloc(sdpy.bufsize);
+    pthread_mutex_init(&sdpy.lock, NULL);
+    register_displaychangelistener(ds, &display_listener);
+
+    sdpy.qxl.base.sif = &dpy_interface.base;
+    spice_server_add_interface(spice_server, &sdpy.qxl.base);
+    assert(sdpy.worker);
+
+    qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy);
+    qemu_spice_create_host_memslot(&sdpy);
+    qemu_spice_create_host_primary(&sdpy);
+}
diff --git a/ui/spice-display.h b/ui/spice-display.h
new file mode 100644
index 0000000..e17671c
--- /dev/null
+++ b/ui/spice-display.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <spice/ipc_ring.h>
+#include <spice/enums.h>
+#include <spice/qxl_dev.h>
+
+#include "pflib.h"
+
+#define NUM_MEMSLOTS 8
+#define MEMSLOT_GENERATION_BITS 8
+#define MEMSLOT_SLOT_BITS 8
+
+#define MEMSLOT_GROUP_HOST  0
+#define MEMSLOT_GROUP_GUEST 1
+#define NUM_MEMSLOTS_GROUPS 2
+
+#define NUM_SURFACES 1024
+
+typedef struct SimpleSpiceDisplay {
+    DisplayState *ds;
+    void *buf;
+    int bufsize;
+    QXLWorker *worker;
+    QXLInstance qxl;
+    uint32_t unique;
+    QemuPfConv *conv;
+
+    pthread_mutex_t lock;
+    QXLRect dirty;
+    int notify;
+    int running;
+} SimpleSpiceDisplay;
+
+typedef struct SimpleSpiceUpdate {
+    QXLDrawable drawable;
+    QXLImage image;
+    QXLCommandExt ext;
+    uint8_t *bitmap;
+} SimpleSpiceUpdate;
+
+int qemu_spice_rect_is_empty(const QXLRect* r);
+void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
+
+SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *sdpy);
+void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update);
+void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
+void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
+void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
+void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
+
+void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+                               int x, int y, int w, int h);
+void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
+void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
diff --git a/vl.c b/vl.c
index a8c2a33..a5229ad 100644
--- a/vl.c
+++ b/vl.c
@@ -2951,6 +2951,11 @@ int main(int argc, char **argv, char **envp)
             printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
         }
     }
+#ifdef CONFIG_SPICE
+    if (using_spice) {
+        qemu_spice_display_init(ds);
+    }
+#endif
 
     /* display setup */
     dpy_resize(ds);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v3 10/10] spice: add tablet support
  2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
                   ` (8 preceding siblings ...)
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 09/10] spice: simple display Gerd Hoffmann
@ 2010-08-25 14:19 ` Gerd Hoffmann
  9 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-25 14:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add support for the spice tablet interface.  The tablet interface will
be registered (and then used by the spice client) as soon as a absolute
pointing device is available and used by the guest, i.e. you'll have to
configure your guest with '-usbdevice tablet'.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 ui/spice-display.c |    2 +-
 ui/spice-input.c   |   91 ++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 85 insertions(+), 8 deletions(-)

diff --git a/ui/spice-display.c b/ui/spice-display.c
index 7163714..6b17be7 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -166,7 +166,7 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
     surface.width      = ds_get_width(ssd->ds);
     surface.height     = ds_get_height(ssd->ds);
     surface.stride     = -surface.width * 4;
-    surface.mouse_mode = 0;
+    surface.mouse_mode = true;
     surface.flags      = 0;
     surface.type       = 0;
     surface.mem        = (intptr_t)ssd->buf;
diff --git a/ui/spice-input.c b/ui/spice-input.c
index 130760d..7cc5aa8 100644
--- a/ui/spice-input.c
+++ b/ui/spice-input.c
@@ -17,6 +17,7 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include <string.h>
 
 #include <spice.h>
@@ -73,9 +74,13 @@ static void kbd_leds(void *opaque, int ledstate)
 
 /* mouse bits */
 
-typedef struct QemuSpiceMouse {
-    SpiceMouseInstance sin;
-} QemuSpiceMouse;
+typedef struct QemuSpicePointer {
+    SpiceMouseInstance  mouse;
+    SpiceTabletInstance tablet;
+    int width, height, x, y;
+    Notifier mouse_mode;
+    bool absolute;
+} QemuSpicePointer;
 
 static int map_buttons(int spice_buttons)
 {
@@ -110,17 +115,89 @@ static const SpiceMouseInterface mouse_interface = {
     .buttons            = mouse_buttons,
 };
 
+static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height)
+{
+    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+    if (height < 16)
+        height = 16;
+    if (width < 16)
+        width = 16;
+    pointer->width  = width;
+    pointer->height = height;
+}
+
+static void tablet_position(SpiceTabletInstance* sin, int x, int y,
+                            uint32_t buttons_state)
+{
+    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+    pointer->x = x * 0x7FFF / (pointer->width - 1);
+    pointer->y = y * 0x7FFF / (pointer->height - 1);
+    kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
+}
+
+
+static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
+                         uint32_t buttons_state)
+{
+    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+    kbd_mouse_event(pointer->x, pointer->y, wheel, map_buttons(buttons_state));
+}
+
+static void tablet_buttons(SpiceTabletInstance *sin,
+                           uint32_t buttons_state)
+{
+    QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
+
+    kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
+}
+
+static const SpiceTabletInterface tablet_interface = {
+    .base.type          = SPICE_INTERFACE_TABLET,
+    .base.description   = "tablet",
+    .base.major_version = SPICE_INTERFACE_TABLET_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_TABLET_MINOR,
+    .set_logical_size   = tablet_set_logical_size,
+    .position           = tablet_position,
+    .wheel              = tablet_wheel,
+    .buttons            = tablet_buttons,
+};
+
+static void mouse_mode_notifier(Notifier *notifier)
+{
+    QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
+    bool is_absolute  = kbd_mouse_is_absolute();
+
+    if (pointer->absolute == is_absolute)
+        return;
+
+    if (is_absolute) {
+        spice_server_add_interface(spice_server, &pointer->tablet.base);
+    } else {
+        spice_server_remove_interface(&pointer->tablet.base);
+    }
+    pointer->absolute = is_absolute;
+}
+
 void qemu_spice_input_init(void)
 {
     QemuSpiceKbd *kbd;
-    QemuSpiceMouse *mouse;
+    QemuSpicePointer *pointer;
 
     kbd = qemu_mallocz(sizeof(*kbd));
     kbd->sin.base.sif = &kbd_interface.base;
     spice_server_add_interface(spice_server, &kbd->sin.base);
     qemu_add_led_event_handler(kbd_leds, kbd);
 
-    mouse = qemu_mallocz(sizeof(*mouse));
-    mouse->sin.base.sif = &mouse_interface.base;
-    spice_server_add_interface(spice_server, &mouse->sin.base);
+    pointer = qemu_mallocz(sizeof(*pointer));
+    pointer->mouse.base.sif  = &mouse_interface.base;
+    pointer->tablet.base.sif = &tablet_interface.base;
+    spice_server_add_interface(spice_server, &pointer->mouse.base);
+
+    pointer->absolute = false;
+    pointer->mouse_mode.notify = mouse_mode_notifier;
+    qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode);
+    mouse_mode_notifier(&pointer->mouse_mode);
 }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/10] spice: add keyboard
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 07/10] spice: add keyboard Gerd Hoffmann
@ 2010-08-25 19:53   ` Anthony Liguori
  2010-08-26  6:55     ` Gerd Hoffmann
  0 siblings, 1 reply; 16+ messages in thread
From: Anthony Liguori @ 2010-08-25 19:53 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On 08/25/2010 09:19 AM, Gerd Hoffmann wrote:
> Open keyboard channel.  Now you can type into the spice client and the
> keyboard events are sent to your guest.  You'll need some other display
> like vnc to actually see the guest responding to them though.
>
> Signed-off-by: Gerd Hoffmann<kraxel@redhat.com>
> ---
>   Makefile.objs    |    2 +-
>   ui/qemu-spice.h  |    1 +
>   ui/spice-core.c  |    2 +
>   ui/spice-input.c |   82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 86 insertions(+), 1 deletions(-)
>   create mode 100644 ui/spice-input.c
>
> diff --git a/Makefile.objs b/Makefile.objs
> index 1a53027..20e6ad7 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -88,7 +88,7 @@ common-obj-y += pflib.o
>   common-obj-$(CONFIG_BRLAPI) += baum.o
>   common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
>
> -common-obj-$(CONFIG_SPICE) += ui/spice-core.o
> +common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o
>
>   audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
>   audio-obj-$(CONFIG_SDL) += sdlaudio.o
> diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
> index d58d74c..75e2502 100644
> --- a/ui/qemu-spice.h
> +++ b/ui/qemu-spice.h
> @@ -29,6 +29,7 @@ extern SpiceServer *spice_server;
>   extern int using_spice;
>
>   void qemu_spice_init(void);
> +void qemu_spice_input_init(void);
>
>   #else  /* CONFIG_SPICE */
>
> diff --git a/ui/spice-core.c b/ui/spice-core.c
> index 3041309..75f0fe9 100644
> --- a/ui/spice-core.c
> +++ b/ui/spice-core.c
> @@ -161,6 +161,8 @@ void qemu_spice_init(void)
>
>       spice_server_init(spice_server,&core_interface);
>       using_spice = 1;
> +
> +    qemu_spice_input_init();
>    

Why not pass spice_server to qemu_spice_input_init() and avoid the global?

Regards,

Anthony Liguori

>   }
>
>   static void spice_register_config(void)
> diff --git a/ui/spice-input.c b/ui/spice-input.c
> new file mode 100644
> index 0000000..d4f44f4
> --- /dev/null
> +++ b/ui/spice-input.c
> @@ -0,0 +1,82 @@
> +/*
> + * Copyright (C) 2010 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 or
> + * (at your option) version 3 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see<http://www.gnu.org/licenses/>.
> + */
> +
> +#include<stdlib.h>
> +#include<stdio.h>
> +#include<string.h>
> +
> +#include<spice.h>
> +#include<spice/enums.h>
> +
> +#include "qemu-common.h"
> +#include "qemu-spice.h"
> +#include "console.h"
> +
> +/* keyboard bits */
> +
> +typedef struct QemuSpiceKbd {
> +    SpiceKbdInstance sin;
> +    int ledstate;
> +} QemuSpiceKbd;
> +
> +static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
> +static uint8_t kbd_get_leds(SpiceKbdInstance *sin);
> +static void kbd_leds(void *opaque, int l);
> +
> +static const SpiceKbdInterface kbd_interface = {
> +    .base.type          = SPICE_INTERFACE_KEYBOARD,
> +    .base.description   = "qemu keyboard",
> +    .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR,
> +    .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR,
> +    .push_scan_freg     = kbd_push_key,
> +    .get_leds           = kbd_get_leds,
> +};
> +
> +static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
> +{
> +    kbd_put_keycode(frag);
> +}
> +
> +static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
> +{
> +    QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
> +    return kbd->ledstate;
> +}
> +
> +static void kbd_leds(void *opaque, int ledstate)
> +{
> +    QemuSpiceKbd *kbd = opaque;
> +
> +    kbd->ledstate = 0;
> +    if (ledstate&  QEMU_SCROLL_LOCK_LED)
> +        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK;
> +    if (ledstate&  QEMU_NUM_LOCK_LED)
> +        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK;
> +    if (ledstate&  QEMU_CAPS_LOCK_LED)
> +        kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK;
> +    spice_server_kbd_leds(&kbd->sin, ledstate);
> +}
> +
> +void qemu_spice_input_init(void)
> +{
> +    QemuSpiceKbd *kbd;
> +
> +    kbd = qemu_mallocz(sizeof(*kbd));
> +    kbd->sin.base.sif =&kbd_interface.base;
> +    spice_server_add_interface(spice_server,&kbd->sin.base);
> +    qemu_add_led_event_handler(kbd_leds, kbd);
> +}
>    

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/10] spice: simple display
  2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 09/10] spice: simple display Gerd Hoffmann
@ 2010-08-25 19:57   ` Anthony Liguori
  2010-08-26  6:56     ` Gerd Hoffmann
  0 siblings, 1 reply; 16+ messages in thread
From: Anthony Liguori @ 2010-08-25 19:57 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On 08/25/2010 09:19 AM, Gerd Hoffmann wrote:
> With that patch applied you'll actually see the guests screen in the
> spice client.  This does *not* bring qxl and full spice support though.
> This is basically the qxl vga mode made more generic, so it plays
> together with any qemu-emulated gfx card.  You can display stdvga or
> cirrus via spice client.  You can have both vnc and spice enabled and
> clients connected at the same time.
>
> Signed-off-by: Gerd Hoffmann<kraxel@redhat.com>
> ---
>   Makefile.objs      |    2 +-
>   ui/qemu-spice.h    |    1 +
>   ui/spice-display.c |  399 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>   ui/spice-display.h |   69 +++++++++
>   vl.c               |    5 +
>   5 files changed, 475 insertions(+), 1 deletions(-)
>   create mode 100644 ui/spice-display.c
>   create mode 100644 ui/spice-display.h
>
> diff --git a/Makefile.objs b/Makefile.objs
> index 20e6ad7..d09a1e4 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -88,7 +88,7 @@ common-obj-y += pflib.o
>   common-obj-$(CONFIG_BRLAPI) += baum.o
>   common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
>
> -common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o
> +common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o
>
>   audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
>   audio-obj-$(CONFIG_SDL) += sdlaudio.o
> diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h
> index 75e2502..5d6e2ea 100644
> --- a/ui/qemu-spice.h
> +++ b/ui/qemu-spice.h
> @@ -30,6 +30,7 @@ extern int using_spice;
>
>   void qemu_spice_init(void);
>   void qemu_spice_input_init(void);
> +void qemu_spice_display_init(DisplayState *ds);
>
>   #else  /* CONFIG_SPICE */
>
> diff --git a/ui/spice-display.c b/ui/spice-display.c
> new file mode 100644
> index 0000000..7163714
> --- /dev/null
> +++ b/ui/spice-display.c
> @@ -0,0 +1,399 @@
> +/*
> + * Copyright (C) 2010 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 or
> + * (at your option) version 3 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see<http://www.gnu.org/licenses/>.
> + */
> +
> +#include<pthread.h>
> +
> +#include "qemu-common.h"
> +#include "qemu-spice.h"
> +#include "qemu-timer.h"
> +#include "qemu-queue.h"
> +#include "monitor.h"
> +#include "console.h"
> +#include "sysemu.h"
> +
> +#include "spice-display.h"
> +
> +static int debug = 0;
> +
> +static void __attribute__((format(printf,2,3)))
> +dprint(int level, const char *fmt, ...)
> +{
> +    va_list args;
> +
> +    if (level<= debug) {
> +        va_start(args, fmt);
> +        vfprintf(stderr, fmt, args);
> +        va_end(args);
> +    }
> +}
> +
> +int qemu_spice_rect_is_empty(const QXLRect* r)
> +{
> +    return r->top == r->bottom || r->left == r->right;
> +}
> +
> +void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
> +{
> +    if (qemu_spice_rect_is_empty(r)) {
> +        return;
> +    }
> +
> +    if (qemu_spice_rect_is_empty(dest)) {
> +        *dest = *r;
> +        return;
> +    }
> +
> +    dest->top = MIN(dest->top, r->top);
> +    dest->left = MIN(dest->left, r->left);
> +    dest->bottom = MAX(dest->bottom, r->bottom);
> +    dest->right = MAX(dest->right, r->right);
> +}
> +
> +/* called from spice server thread context (via interface_get_command) */
> +SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
> +{
> +    SimpleSpiceUpdate *update;
> +    QXLDrawable *drawable;
> +    QXLImage *image;
> +    QXLCommand *cmd;
> +    uint8_t *src, *dst;
> +    int by, bw, bh;
> +
> +    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
> +        return NULL;
> +    };
> +
> +    pthread_mutex_lock(&ssd->lock);
> +    dprint(2, "%s: lr %d ->  %d,  tb ->  %d ->  %d\n", __FUNCTION__,
> +           ssd->dirty.left, ssd->dirty.right,
> +           ssd->dirty.top, ssd->dirty.bottom);
> +
> +    update   = qemu_mallocz(sizeof(*update));
> +    drawable =&update->drawable;
> +    image    =&update->image;
> +    cmd      =&update->ext.cmd;
> +
> +    bw       = ssd->dirty.right - ssd->dirty.left;
> +    bh       = ssd->dirty.bottom - ssd->dirty.top;
> +    update->bitmap = qemu_malloc(bw * bh * 4);
> +
> +    drawable->bbox            = ssd->dirty;
> +    drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
> +    drawable->effect          = QXL_EFFECT_OPAQUE;
> +    drawable->release_info.id = (intptr_t)update;
> +    drawable->type            = QXL_DRAW_COPY;
> +
> +    drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
> +    drawable->u.copy.src_bitmap      = (intptr_t)image;
> +    drawable->u.copy.src_area.right  = bw;
> +    drawable->u.copy.src_area.bottom = bh;
> +
> +    QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++);
> +    image->descriptor.type   = SPICE_IMAGE_TYPE_BITMAP;
> +    image->bitmap.flags      = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
> +    image->bitmap.stride     = bw * 4;
> +    image->descriptor.width  = image->bitmap.x = bw;
> +    image->descriptor.height = image->bitmap.y = bh;
> +    image->bitmap.data = (intptr_t)(update->bitmap);
> +    image->bitmap.palette = 0;
> +    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
> +
> +    if (ssd->conv == NULL) {
> +        PixelFormat dst = qemu_default_pixelformat(32);
> +        ssd->conv = qemu_pf_conv_get(&dst,&ssd->ds->surface->pf);
> +        assert(ssd->conv);
> +    }
> +
> +    src = ds_get_data(ssd->ds) +
> +        ssd->dirty.top * ds_get_linesize(ssd->ds) +
> +        ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds);
> +    dst = update->bitmap;
> +    for (by = 0; by<  bh; by++) {
> +        qemu_pf_conv_run(ssd->conv, dst, src, bw);
> +        src += ds_get_linesize(ssd->ds);
> +        dst += image->bitmap.stride;
> +    }
> +
> +    cmd->type = QXL_CMD_DRAW;
> +    cmd->data = (intptr_t)drawable;
> +
> +    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
> +    pthread_mutex_unlock(&ssd->lock);
> +    return update;
> +}
> +
> +/* called from spice server thread context (via interface_release_ressource) */
>    

There's still the implicit assumption that the reader understands that 
we're not carrying the global mutex here and that we're relying on the 
functions used to be re-entrant.  I think we need a big scary warning 
here otherwise it's just far too easy to break this code.

Regards,

Anthony Liguori

> +void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update)
> +{
> +    qemu_free(update->bitmap);
> +    qemu_free(update);
> +}
> +
> +void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
> +{
> +    QXLDevMemSlot memslot;
> +
> +    dprint(1, "%s:\n", __FUNCTION__);
> +
> +    memset(&memslot, 0, sizeof(memslot));
> +    memslot.slot_group_id = MEMSLOT_GROUP_HOST;
> +    memslot.virt_end = ~0;
> +    ssd->worker->add_memslot(ssd->worker,&memslot);
> +}
> +
> +void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
> +{
> +    QXLDevSurfaceCreate surface;
> +
> +    dprint(1, "%s: %dx%d\n", __FUNCTION__,
> +           ds_get_width(ssd->ds), ds_get_height(ssd->ds));
> +
> +    surface.format     = SPICE_SURFACE_FMT_32_xRGB;
> +    surface.width      = ds_get_width(ssd->ds);
> +    surface.height     = ds_get_height(ssd->ds);
> +    surface.stride     = -surface.width * 4;
> +    surface.mouse_mode = 0;
> +    surface.flags      = 0;
> +    surface.type       = 0;
> +    surface.mem        = (intptr_t)ssd->buf;
> +    surface.group_id   = MEMSLOT_GROUP_HOST;
> +    ssd->worker->create_primary_surface(ssd->worker, 0,&surface);
> +}
> +
> +void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
> +{
> +    dprint(1, "%s:\n", __FUNCTION__);
> +
> +    ssd->worker->destroy_primary_surface(ssd->worker, 0);
> +}
> +
> +void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
> +{
> +    SimpleSpiceDisplay *ssd = opaque;
> +
> +    if (running) {
> +        ssd->worker->start(ssd->worker);
> +    } else {
> +        ssd->worker->stop(ssd->worker);
> +    }
> +    ssd->running = running;
> +}
> +
> +/* display listener callbacks */
> +
> +void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
> +                               int x, int y, int w, int h)
> +{
> +    QXLRect update_area;
> +
> +    dprint(2, "%s: x %d y %d w %d h %d\n", __FUNCTION__, x, y, w, h);
> +    update_area.left = x,
> +    update_area.right = x + w;
> +    update_area.top = y;
> +    update_area.bottom = y + h;
> +
> +    pthread_mutex_lock(&ssd->lock);
> +    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
> +        ssd->notify++;
> +    }
> +    qemu_spice_rect_union(&ssd->dirty,&update_area);
> +    pthread_mutex_unlock(&ssd->lock);
> +}
> +
> +void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
> +{
> +    dprint(1, "%s:\n", __FUNCTION__);
> +
> +    pthread_mutex_lock(&ssd->lock);
> +    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
> +    qemu_pf_conv_put(ssd->conv);
> +    ssd->conv = NULL;
> +    pthread_mutex_unlock(&ssd->lock);
> +
> +    qemu_spice_destroy_host_primary(ssd);
> +    qemu_spice_create_host_primary(ssd);
> +
> +    pthread_mutex_lock(&ssd->lock);
> +    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
> +    ssd->notify++;
> +    pthread_mutex_unlock(&ssd->lock);
> +}
> +
> +void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
> +{
> +    dprint(3, "%s:\n", __FUNCTION__);
> +    vga_hw_update();
> +    if (ssd->notify) {
> +        ssd->notify = 0;
> +        ssd->worker->wakeup(ssd->worker);
> +        if (debug>  1)
> +            fprintf(stderr, "%s: notify\n", __FUNCTION__);
> +    }
> +}
> +
> +/* spice display interface callbacks */
> +
> +static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
> +{
> +    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
> +
> +    dprint(1, "%s:\n", __FUNCTION__);
> +    ssd->worker = qxl_worker;
> +}
> +
> +static void interface_set_compression_level(QXLInstance *sin, int level)
> +{
> +    dprint(1, "%s:\n", __FUNCTION__);
> +    /* nothing to do */
> +}
> +
> +static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
> +{
> +    dprint(3, "%s:\n", __FUNCTION__);
> +    /* nothing to do */
> +}
> +
> +static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
> +{
> +    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
> +
> +    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
> +    info->memslot_id_bits  = MEMSLOT_SLOT_BITS;
> +    info->num_memslots = NUM_MEMSLOTS;
> +    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
> +    info->internal_groupslot_id = 0;
> +    info->qxl_ram_size = ssd->bufsize;
> +    info->n_surfaces = NUM_SURFACES;
> +}
> +
> +static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
> +{
> +    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
> +    SimpleSpiceUpdate *update;
> +
> +    dprint(3, "%s:\n", __FUNCTION__);
> +    update = qemu_spice_create_update(ssd);
> +    if (update == NULL) {
> +        return false;
> +    }
> +    *ext = update->ext;
> +    return true;
> +}
> +
> +static int interface_req_cmd_notification(QXLInstance *sin)
> +{
> +    dprint(1, "%s:\n", __FUNCTION__);
> +    return 1;
> +}
> +
> +static void interface_release_resource(QXLInstance *sin,
> +                                       struct QXLReleaseInfoExt ext)
> +{
> +    SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
> +    uintptr_t id;
> +
> +    dprint(2, "%s:\n", __FUNCTION__);
> +    id = ext.info->id;
> +    qemu_spice_destroy_update(ssd, (void*)id);
> +}
> +
> +static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
> +{
> +    dprint(3, "%s:\n", __FUNCTION__);
> +    return false;
> +}
> +
> +static int interface_req_cursor_notification(QXLInstance *sin)
> +{
> +    dprint(1, "%s:\n", __FUNCTION__);
> +    return 1;
> +}
> +
> +static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
> +{
> +    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
> +    abort();
> +}
> +
> +static int interface_flush_resources(QXLInstance *sin)
> +{
> +    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
> +    abort();
> +    return 0;
> +}
> +
> +static const QXLInterface dpy_interface = {
> +    .base.type               = SPICE_INTERFACE_QXL,
> +    .base.description        = "qemu simple display",
> +    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
> +    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
> +
> +    .attache_worker          = interface_attach_worker,
> +    .set_compression_level   = interface_set_compression_level,
> +    .set_mm_time             = interface_set_mm_time,
> +    .get_init_info           = interface_get_init_info,
> +
> +    /* the callbacks below are called from spice server thread context */
> +    .get_command             = interface_get_command,
> +    .req_cmd_notification    = interface_req_cmd_notification,
> +    .release_resource        = interface_release_resource,
> +    .get_cursor_command      = interface_get_cursor_command,
> +    .req_cursor_notification = interface_req_cursor_notification,
> +    .notify_update           = interface_notify_update,
> +    .flush_resources         = interface_flush_resources,
> +};
> +
> +static SimpleSpiceDisplay sdpy;
> +
> +static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
> +{
> +    qemu_spice_display_update(&sdpy, x, y, w, h);
> +}
> +
> +static void display_resize(struct DisplayState *ds)
> +{
> +    qemu_spice_display_resize(&sdpy);
> +}
> +
> +static void display_refresh(struct DisplayState *ds)
> +{
> +    qemu_spice_display_refresh(&sdpy);
> +}
> +
> +static DisplayChangeListener display_listener = {
> +    .dpy_update  = display_update,
> +    .dpy_resize  = display_resize,
> +    .dpy_refresh = display_refresh,
> +};
> +
> +void qemu_spice_display_init(DisplayState *ds)
> +{
> +    assert(sdpy.ds == NULL);
> +    sdpy.ds = ds;
> +    sdpy.bufsize = (16 * 1024 * 1024);
> +    sdpy.buf = qemu_malloc(sdpy.bufsize);
> +    pthread_mutex_init(&sdpy.lock, NULL);
> +    register_displaychangelistener(ds,&display_listener);
> +
> +    sdpy.qxl.base.sif =&dpy_interface.base;
> +    spice_server_add_interface(spice_server,&sdpy.qxl.base);
> +    assert(sdpy.worker);
> +
> +    qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler,&sdpy);
> +    qemu_spice_create_host_memslot(&sdpy);
> +    qemu_spice_create_host_primary(&sdpy);
> +}
> diff --git a/ui/spice-display.h b/ui/spice-display.h
> new file mode 100644
> index 0000000..e17671c
> --- /dev/null
> +++ b/ui/spice-display.h
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright (C) 2010 Red Hat, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 or
> + * (at your option) version 3 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see<http://www.gnu.org/licenses/>.
> + */
> +
> +#include<spice/ipc_ring.h>
> +#include<spice/enums.h>
> +#include<spice/qxl_dev.h>
> +
> +#include "pflib.h"
> +
> +#define NUM_MEMSLOTS 8
> +#define MEMSLOT_GENERATION_BITS 8
> +#define MEMSLOT_SLOT_BITS 8
> +
> +#define MEMSLOT_GROUP_HOST  0
> +#define MEMSLOT_GROUP_GUEST 1
> +#define NUM_MEMSLOTS_GROUPS 2
> +
> +#define NUM_SURFACES 1024
> +
> +typedef struct SimpleSpiceDisplay {
> +    DisplayState *ds;
> +    void *buf;
> +    int bufsize;
> +    QXLWorker *worker;
> +    QXLInstance qxl;
> +    uint32_t unique;
> +    QemuPfConv *conv;
> +
> +    pthread_mutex_t lock;
> +    QXLRect dirty;
> +    int notify;
> +    int running;
> +} SimpleSpiceDisplay;
> +
> +typedef struct SimpleSpiceUpdate {
> +    QXLDrawable drawable;
> +    QXLImage image;
> +    QXLCommandExt ext;
> +    uint8_t *bitmap;
> +} SimpleSpiceUpdate;
> +
> +int qemu_spice_rect_is_empty(const QXLRect* r);
> +void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
> +
> +SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *sdpy);
> +void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update);
> +void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd);
> +void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd);
> +void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd);
> +void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason);
> +
> +void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
> +                               int x, int y, int w, int h);
> +void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
> +void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
> diff --git a/vl.c b/vl.c
> index a8c2a33..a5229ad 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -2951,6 +2951,11 @@ int main(int argc, char **argv, char **envp)
>               printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
>           }
>       }
> +#ifdef CONFIG_SPICE
> +    if (using_spice) {
> +        qemu_spice_display_init(ds);
> +    }
> +#endif
>
>       /* display setup */
>       dpy_resize(ds);
>    

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/10] spice: add keyboard
  2010-08-25 19:53   ` Anthony Liguori
@ 2010-08-26  6:55     ` Gerd Hoffmann
  2010-08-26 12:55       ` Anthony Liguori
  0 siblings, 1 reply; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-26  6:55 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

   Hi,

>> +
>> + qemu_spice_input_init();
>
> Why not pass spice_server to qemu_spice_input_init() and avoid the global?
>

We need the global anyway for the guest devices (not yet in this 
series).  They are created using -device.  Thus the initialization 
functions are not called from spice code and we can't simply pass a 
reference to spice_server.

cheers,
   Gerd

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/10] spice: simple display
  2010-08-25 19:57   ` Anthony Liguori
@ 2010-08-26  6:56     ` Gerd Hoffmann
  0 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2010-08-26  6:56 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

>> +/* called from spice server thread context (via
>> interface_release_ressource) */
>
> There's still the implicit assumption that the reader understands that
> we're not carrying the global mutex here and that we're relying on the
> functions used to be re-entrant. I think we need a big scary warning
> here otherwise it's just far too easy to break this code.

Ok, I'll make it more verbose.

cheers,
   Gerd

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/10] spice: add keyboard
  2010-08-26  6:55     ` Gerd Hoffmann
@ 2010-08-26 12:55       ` Anthony Liguori
  0 siblings, 0 replies; 16+ messages in thread
From: Anthony Liguori @ 2010-08-26 12:55 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On 08/26/2010 01:55 AM, Gerd Hoffmann wrote:
>   Hi,
>
>>> +
>>> + qemu_spice_input_init();
>>
>> Why not pass spice_server to qemu_spice_input_init() and avoid the 
>> global?
>>
>
> We need the global anyway for the guest devices (not yet in this 
> series).  They are created using -device.  Thus the initialization 
> functions are not called from spice code and we can't simply pass a 
> reference to spice_server.

Let's avoid it where we can and we'll do what we need to do for the 
guest devices.

In general, for the cases that we truly need a global, I'd prefer 
getting to it via a function instead of having a non-static variable.

Regards,

Anthony Liguori

>
> cheers,
>   Gerd

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2010-08-26 12:55 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-08-25 14:19 [Qemu-devel] [PATCH v3 00/10] initial spice support Gerd Hoffmann
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 01/10] Use display types for local display only Gerd Hoffmann
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 02/10] Use machine_init() to register virtfs config options Gerd Hoffmann
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 03/10] add pflib: PixelFormat conversion library Gerd Hoffmann
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 04/10] configure: add logging Gerd Hoffmann
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 05/10] add spice into the configure file Gerd Hoffmann
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 06/10] spice: core bits Gerd Hoffmann
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 07/10] spice: add keyboard Gerd Hoffmann
2010-08-25 19:53   ` Anthony Liguori
2010-08-26  6:55     ` Gerd Hoffmann
2010-08-26 12:55       ` Anthony Liguori
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 08/10] spice: add mouse Gerd Hoffmann
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 09/10] spice: simple display Gerd Hoffmann
2010-08-25 19:57   ` Anthony Liguori
2010-08-26  6:56     ` Gerd Hoffmann
2010-08-25 14:19 ` [Qemu-devel] [PATCH v3 10/10] spice: add tablet support Gerd Hoffmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).