From 3a67f1fa10df7aab7c1389aa781224613de401aa Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 24 Mar 2010 08:43:12 -0300
Subject: [PATCH 01/14] spice: add tablet

RH-Author: Gerd Hoffmann <kraxel@redhat.com>
Message-id: <1269420192-16481-1-git-send-email-kraxel@redhat.com>
Patchwork-id: 8082
O-Subject: [RHEL-6 kvm PATCH v3] spice: add tablet
Bugzilla: 574211
RH-Acked-by: Yonit Halperin <yhalperi@redhat.com>
RH-Acked-by: Alexander Larsson <alexl@redhat.com>
RH-Acked-by: Juan Quintela <quintela@redhat.com>

Open tablet channel.  Absolute positioning (aka client mouse mode)
works now.  As soon as the guest activates the usb tablet the
switchover happens automatically.

[ update: Register spice tablet interface only in case we see the
  guest using a absolute pointing device (aka usb tablet) instead
  of doing it unconditionally. ]

[ v2: make have_tablet bool ]
[ v3: more have_tablet bool fixes ]

bugzilla: #574211 -- spice: add tablet support

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/qxl.c        |    1 +
 qemu-spice.h    |    1 +
 spice-display.c |    1 +
 spice-input.c   |   81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 84 insertions(+), 0 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 hw/qxl.c        |    1 +
 qemu-spice.h    |    1 +
 spice-display.c |    1 +
 spice-input.c   |   81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/hw/qxl.c b/hw/qxl.c
index 732c546..233fb66 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -816,6 +816,7 @@ static void qxl_display_resize(struct DisplayState *ds)
             pthread_mutex_unlock(&dirty_lock);
         }
     }
+    qemu_spice_tablet_size(ds_get_width(ds), ds_get_height(ds));
 }
 
 static void qxl_display_refresh(struct DisplayState *ds)
diff --git a/qemu-spice.h b/qemu-spice.h
index 3071160..4d3e837 100644
--- a/qemu-spice.h
+++ b/qemu-spice.h
@@ -13,6 +13,7 @@ extern int using_spice;
 
 void qemu_spice_init(void);
 void qemu_spice_input_init(SpiceServer *s);
+void qemu_spice_tablet_size(int width, int height);
 void qemu_spice_display_init(DisplayState *ds);
 
 void qxl_display_init(DisplayState *ds);
diff --git a/spice-display.c b/spice-display.c
index 54c7663..a3441ab 100644
--- a/spice-display.c
+++ b/spice-display.c
@@ -139,6 +139,7 @@ static void spice_display_resize(struct DisplayState *ds)
         sdpy.is_attached = 1;
         sdpy.worker->attach(sdpy.worker);
     }
+    qemu_spice_tablet_size(ds_get_width(ds), ds_get_height(ds));
 }
 
 static void spice_display_refresh(struct DisplayState *ds)
diff --git a/spice-input.c b/spice-input.c
index 56a1c8c..f8454fc 100644
--- a/spice-input.c
+++ b/spice-input.c
@@ -1,6 +1,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdbool.h>
 
 #include <spice.h>
 
@@ -11,7 +12,11 @@
 /* keyboard bits */
 
 static int ledstate;
+static bool have_tablet;
+static SpiceServer *spice_state;
+static int abs_x, abs_y, abs_width, abs_height;
 
+static void qemu_spice_tablet_mode(bool enabled);
 static void kbd_push_scan_freg(KeyboardInterface *keyboard, uint8_t frag);
 static uint8_t kbd_get_leds(KeyboardInterface *keyboard);
 static void kbd_leds(void *opaque, int l);
@@ -48,6 +53,14 @@ static void kbd_leds(void *opaque, int l)
 static void mouse_motion(MouseInterface* mouse, int dx, int dy, int dz,
                          uint32_t buttons_state)
 {
+    if (kbd_mouse_is_absolute()) {
+        /*
+         * We'll arrive here when the guest activates some input
+         * device with absolute positioning, i.e. usb tablet.
+         */
+        qemu_spice_tablet_mode(true);
+        return;
+    }
     kbd_mouse_event(dx, dy, dz, buttons_state);
 }
 
@@ -66,9 +79,77 @@ static MouseInterface mouse_interface = {
     .buttons = mouse_buttons,
 };
 
+/* tablet bits */
+
+static void tablet_set_logical_size(TabletInterface* interface, int width, int height)
+{
+    abs_width  = width;
+    abs_height = height;
+}
+
+static void tablet_position(TabletInterface *interface, int x, int y,
+                            uint32_t buttons_state)
+{
+    if (!kbd_mouse_is_absolute()) {
+        qemu_spice_tablet_mode(false);
+        return;
+    }
+    abs_x = x * 0x7FFF / (abs_width - 1);
+    abs_y = y * 0x7FFF / (abs_height - 1);
+    kbd_mouse_event(abs_x, abs_y, 0, buttons_state);
+}
+
+
+static void tablet_wheel(TabletInterface *interface, int wheel,
+                         uint32_t buttons_state)
+{
+    kbd_mouse_event(abs_x, abs_y, wheel, buttons_state);
+}
+
+static void tablet_buttons(TabletInterface *interface,
+                           uint32_t buttons_state)
+{
+    kbd_mouse_event(abs_x, abs_y, 0, buttons_state);
+}
+
+static TabletInterface tablet_interface = {
+    .base.base_version = VM_INTERFACE_VERSION,
+    .base.type = VD_INTERFACE_TABLET,
+    .base.description = "tablet",
+    .base.major_version = VD_INTERFACE_TABLET_MAJOR,
+    .base.minor_version = VD_INTERFACE_TABLET_MINOR,
+    .set_logical_size = tablet_set_logical_size,
+    .position = tablet_position,
+    .wheel = tablet_wheel,
+    .buttons = tablet_buttons,
+};
+
 void qemu_spice_input_init(SpiceServer *s)
 {
+    spice_state = s;
     qemu_add_led_event_handler(kbd_leds, s);
     qemu_spice_add_interface(&kbd_interface.base);
     qemu_spice_add_interface(&mouse_interface.base);
 }
+
+static void qemu_spice_tablet_mode(bool enabled)
+{
+    if (enabled) {
+        if (!have_tablet) {
+            qemu_spice_add_interface(&tablet_interface.base);
+            have_tablet = true;
+        }
+        spice_server_set_mouse_absolute(spice_state, 1);
+    } else {
+        if (have_tablet) {
+            qemu_spice_remove_interface(&tablet_interface.base);
+            have_tablet = false;
+        }
+        spice_server_set_mouse_absolute(spice_state, 0);
+    }
+}
+
+void qemu_spice_tablet_size(int width, int height)
+{
+    tablet_set_logical_size(&tablet_interface, width, height);
+}
-- 
1.6.3.rc4.29.g8146

