On Fri, Apr 23, 2021 at 12:34 PM Gerd Hoffmann <kra...@redhat.com> wrote:

> This patch adds support for mouse messages to the vdagent
> implementation.  This can be enabled/disabled using the new
> 'mouse' parameter for the vdagent chardev.  Default is on.
>
> Signed-off-by: Gerd Hoffmann <kra...@redhat.com>
>

Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com>

---
>  chardev/char.c |   3 +
>  ui/vdagent.c   | 150 +++++++++++++++++++++++++++++++++++++++++++++++++
>  qapi/char.json |   4 +-
>  3 files changed, 156 insertions(+), 1 deletion(-)
>
> diff --git a/chardev/char.c b/chardev/char.c
> index 398f09df19cd..9714057541fb 100644
> --- a/chardev/char.c
> +++ b/chardev/char.c
> @@ -932,6 +932,9 @@ QemuOptsList qemu_chardev_opts = {
>          },{
>              .name = "logappend",
>              .type = QEMU_OPT_BOOL,
> +        },{
> +            .name = "mouse",
> +            .type = QEMU_OPT_BOOL,
>  #ifdef CONFIG_LINUX
>          },{
>              .name = "tight",
> diff --git a/ui/vdagent.c b/ui/vdagent.c
> index 98d1a2ee3415..e914a33bae20 100644
> --- a/ui/vdagent.c
> +++ b/ui/vdagent.c
> @@ -1,15 +1,25 @@
>  #include "qemu/osdep.h"
>  #include "include/qemu-common.h"
>  #include "chardev/char.h"
> +#include "hw/qdev-core.h"
> +#include "qemu/option.h"
> +#include "ui/console.h"
> +#include "ui/input.h"
>  #include "trace.h"
>
>  #include "qapi/qapi-types-char.h"
> +#include "qapi/qapi-types-ui.h"
>
>  #include "spice/vd_agent.h"
>
> +#define VDAGENT_MOUSE_DEFAULT true
> +
>  struct VDAgentChardev {
>      Chardev parent;
>
> +    /* config */
> +    bool mouse;
> +
>      /* guest vdagent */
>      uint32_t caps;
>      VDIChunkHeader chunk;
> @@ -18,6 +28,14 @@ struct VDAgentChardev {
>      uint32_t msgsize;
>      uint8_t *xbuf;
>      uint32_t xoff, xsize;
> +
> +    /* mouse */
> +    DeviceState mouse_dev;
> +    uint32_t mouse_x;
> +    uint32_t mouse_y;
> +    uint32_t mouse_btn;
> +    uint32_t mouse_display;
> +    QemuInputHandlerState *mouse_hs;
>  };
>  typedef struct VDAgentChardev VDAgentChardev;
>
> @@ -122,13 +140,113 @@ static void vdagent_send_caps(VDAgentChardev *vd)
>      g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
>
> sizeof(VDAgentAnnounceCapabilities) +
>                                                 sizeof(uint32_t));
> +    VDAgentAnnounceCapabilities *caps = (void *)msg->data;
>
>      msg->type = VD_AGENT_ANNOUNCE_CAPABILITIES;
>      msg->size = sizeof(VDAgentAnnounceCapabilities) + sizeof(uint32_t);
> +    if (vd->mouse) {
> +        caps->caps[0] |= (1 << VD_AGENT_CAP_MOUSE_STATE);
> +    }
>
>      vdagent_send_msg(vd, msg);
>  }
>
> +/* ------------------------------------------------------------------ */
> +/* mouse events                                                       */
> +
> +static bool have_mouse(VDAgentChardev *vd)
> +{
> +    return vd->mouse &&
> +        (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE));
> +}
> +
> +static void vdagent_send_mouse(VDAgentChardev *vd)
> +{
> +    g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
> +                                               sizeof(VDAgentMouseState));
> +    VDAgentMouseState *mouse = (void *)msg->data;
> +
> +    msg->type = VD_AGENT_MOUSE_STATE;
> +    msg->size = sizeof(VDAgentMouseState);
> +
> +    mouse->x          = vd->mouse_x;
> +    mouse->y          = vd->mouse_y;
> +    mouse->buttons    = vd->mouse_btn;
> +    mouse->display_id = vd->mouse_display;
> +
> +    vdagent_send_msg(vd, msg);
> +}
> +
> +static void vdagent_pointer_event(DeviceState *dev, QemuConsole *src,
> +                                  InputEvent *evt)
> +{
> +    static const int bmap[INPUT_BUTTON__MAX] = {
> +        [INPUT_BUTTON_LEFT]        = VD_AGENT_LBUTTON_MASK,
> +        [INPUT_BUTTON_RIGHT]       = VD_AGENT_RBUTTON_MASK,
> +        [INPUT_BUTTON_MIDDLE]      = VD_AGENT_MBUTTON_MASK,
> +        [INPUT_BUTTON_WHEEL_UP]    = VD_AGENT_UBUTTON_MASK,
> +        [INPUT_BUTTON_WHEEL_DOWN]  = VD_AGENT_DBUTTON_MASK,
> +#if 0
> +        [INPUT_BUTTON_SIDE]        = VD_AGENT_SBUTTON_MASK,
> +        [INPUT_BUTTON_EXTRA]       = VD_AGENT_EBUTTON_MASK,
> +#endif
> +    };
> +
> +    VDAgentChardev *vd = container_of(dev, struct VDAgentChardev,
> mouse_dev);
> +    InputMoveEvent *move;
> +    InputBtnEvent *btn;
> +    uint32_t xres, yres;
> +
> +    switch (evt->type) {
> +    case INPUT_EVENT_KIND_ABS:
> +        move = evt->u.abs.data;
> +        xres = qemu_console_get_width(src, 1024);
> +        yres = qemu_console_get_height(src, 768);
> +        if (move->axis == INPUT_AXIS_X) {
> +            vd->mouse_x = qemu_input_scale_axis(move->value,
> +                                                INPUT_EVENT_ABS_MIN,
> +                                                INPUT_EVENT_ABS_MAX,
> +                                                0, xres);
> +        } else if (move->axis == INPUT_AXIS_Y) {
> +            vd->mouse_y = qemu_input_scale_axis(move->value,
> +                                                INPUT_EVENT_ABS_MIN,
> +                                                INPUT_EVENT_ABS_MAX,
> +                                                0, yres);
> +        }
> +        vd->mouse_display = qemu_console_get_index(src);
> +        break;
> +
> +    case INPUT_EVENT_KIND_BTN:
> +        btn = evt->u.btn.data;
> +        if (btn->down) {
> +            vd->mouse_btn |= bmap[btn->button];
> +        } else {
> +            vd->mouse_btn &= ~bmap[btn->button];
> +        }
> +        break;
> +
> +    default:
> +        /* keep gcc happy */
> +        break;
> +    }
> +}
> +
> +static void vdagent_pointer_sync(DeviceState *dev)
> +{
> +    VDAgentChardev *vd = container_of(dev, struct VDAgentChardev,
> mouse_dev);
> +
> +    if (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE)) {
> +        vdagent_send_mouse(vd);
> +    }
> +}
> +
> +static QemuInputHandler vdagent_mouse_handler = {
> +    .name  = "vdagent mouse",
> +    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
> +    .event = vdagent_pointer_event,
> +    .sync  = vdagent_pointer_sync,
> +};
> +
>  /* ------------------------------------------------------------------ */
>  /* chardev backend                                                    */
>
> @@ -137,6 +255,19 @@ static void vdagent_chr_open(Chardev *chr,
>                               bool *be_opened,
>                               Error **errp)
>  {
> +    VDAgentChardev *vd = VDAGENT_CHARDEV(chr);
> +    ChardevVDAgent *cfg = backend->u.vdagent.data;
> +
> +    vd->mouse = VDAGENT_MOUSE_DEFAULT;
> +    if (cfg->has_mouse) {
> +        vd->mouse = cfg->mouse;
> +    }
> +
> +    if (vd->mouse) {
> +        vd->mouse_hs = qemu_input_handler_register(&vd->mouse_dev,
> +
>  &vdagent_mouse_handler);
> +    }
> +
>      *be_opened = true;
>  }
>
> @@ -160,6 +291,9 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd,
> VDAgentMessage *msg)
>      if (caps->request) {
>          vdagent_send_caps(vd);
>      }
> +    if (have_mouse(vd) && vd->mouse_hs) {
> +        qemu_input_handler_activate(vd->mouse_hs);
> +    }
>  }
>
>  static void vdagent_chr_recv_msg(VDAgentChardev *vd, VDAgentMessage *msg)
> @@ -282,18 +416,34 @@ static void vdagent_chr_set_fe_open(struct Chardev
> *chr, int fe_open)
>          /* reset state */
>          vdagent_reset_bufs(vd);
>          vd->caps = 0;
> +        if (vd->mouse_hs) {
> +            qemu_input_handler_deactivate(vd->mouse_hs);
> +        }
>          return;
>      }
>
>      trace_vdagent_open();
>  }
>
> +static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend,
> +                              Error **errp)
> +{
> +    ChardevVDAgent *cfg;
> +
> +    backend->type = CHARDEV_BACKEND_KIND_VDAGENT;
> +    cfg = backend->u.vdagent.data = g_new0(ChardevVDAgent, 1);
> +    qemu_chr_parse_common(opts, qapi_ChardevVDAgent_base(cfg));
> +    cfg->has_mouse = true;
> +    cfg->mouse = qemu_opt_get_bool(opts, "mouse", VDAGENT_MOUSE_DEFAULT);
> +}
> +
>  /* ------------------------------------------------------------------ */
>
>  static void vdagent_chr_class_init(ObjectClass *oc, void *data)
>  {
>      ChardevClass *cc = CHARDEV_CLASS(oc);
>
> +    cc->parse            = vdagent_chr_parse;
>      cc->open             = vdagent_chr_open;
>      cc->chr_write        = vdagent_chr_write;
>      cc->chr_set_fe_open  = vdagent_chr_set_fe_open;
> diff --git a/qapi/char.json b/qapi/char.json
> index ca5a85f76b3e..880aa8f73333 100644
> --- a/qapi/char.json
> +++ b/qapi/char.json
> @@ -395,11 +395,13 @@
>  #
>  # Configuration info for vdagent.
>  #
> +# @mouse: enable/disable mouse, default is enabled.
> +#
>  # Since: 6.1
>  #
>  ##
>  { 'struct': 'ChardevVDAgent',
> -  'data': { },
> +  'data': { '*mouse': 'bool' },
>    'base': 'ChardevCommon',
>    'if': 'defined(CONFIG_SPICE_PROTOCOL)' }
>
> --
> 2.30.2
>
>

Reply via email to