@ -3,18 +3,27 @@
# include "include/qemu-common.h"
# include "chardev/char.h"
# include "qemu/buffer.h"
# include "qemu/option.h"
# include "qemu/units.h"
# include "hw/qdev-core.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_BUFFER_LIMIT (1 * MiB)
# define VDAGENT_MOUSE_DEFAULT true
struct VDAgentChardev {
Chardev parent ;
/* config */
bool mouse ;
/* guest vdagent */
uint32_t caps ;
VDIChunkHeader chunk ;
@ -24,6 +33,14 @@ struct VDAgentChardev {
uint8_t * xbuf ;
uint32_t xoff , xsize ;
Buffer outbuf ;
/* 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 ;
@ -137,13 +154,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 ,
# ifdef VD_AGENT_EBUTTON_MASK
[ 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 */
@ -152,6 +269,9 @@ static void vdagent_chr_open(Chardev *chr,
bool * be_opened ,
Error * * errp )
{
VDAgentChardev * vd = QEMU_VDAGENT_CHARDEV ( chr ) ;
ChardevQemuVDAgent * cfg = backend - > u . qemu_vdagent . data ;
# if defined(HOST_WORDS_BIGENDIAN)
/*
* TODO : vdagent protocol is defined to be LE ,
@ -161,6 +281,16 @@ static void vdagent_chr_open(Chardev *chr,
return ;
# endif
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 ;
}
@ -184,6 +314,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 )
@ -312,18 +445,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 )
{
ChardevQemuVDAgent * cfg ;
backend - > type = CHARDEV_BACKEND_KIND_QEMU_VDAGENT ;
cfg = backend - > u . qemu_vdagent . data = g_new0 ( ChardevQemuVDAgent , 1 ) ;
qemu_chr_parse_common ( opts , qapi_ChardevQemuVDAgent_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 ;