spice工作过程,相当繁琐。其中经过组件依次为
1.客户端(例如spicec,spicy)
2.spice-server
3.qemu-kvm
4.guest
具体流程可参照网上资料,下面分析spice鼠标移动事件工作过程,spice鼠标相对其他是比较简单的。
1.客户端spice mouse鼠标的移动操作
<1>鼠标在Linux spice客户端进行移动时
<2>X11引擎捕获该事件
<3>发送鼠标移动信息给spice server.
<4>客户端进行鼠标设置
void RedWindow_p::win_proc(XEvent& event)
{
switch (event.type) {
case MotionNotify: {
SpicePoint size = red_window->get_size();
if (event.xmotion.x >= 0 && event.xmotion.y >= 0 &&
event.xmotion.x < size.x && event.xmotion.y < size.y) {
SpicePoint origin = red_window->get_origin();
red_window->get_listener().on_pointer_motion(event.xmotion.x - origin.x,
event.xmotion.y - origin.y,
to_red_buttons_state(event.xmotion.state));
}
break;
}
}
void RedScreen::on_pointer_motion(int x, int y, unsigned int buttons_state)
{
if (_mouse_captured) {
on_mouse_motion(x, y, buttons_state);
return;
}
_pointer_pos.x = x;
_pointer_pos.y = y;
_mouse_botton_state = buttons_state;
if (update_pointer_layer() || !_pointer_layer) {
return;
}
_pointer_layer->on_pointer_motion(x, y, buttons_state);
}
void RedScreen::on_mouse_motion(int x, int y, unsigned int buttons_state)
{
if (x != _mouse_anchor_point.x || y != _mouse_anchor_point.y) {
_owner.on_mouse_motion(x - _mouse_anchor_point.x,
y - _mouse_anchor_point.y,
buttons_state);
reset_mouse_pos();
}
}
void Application::on_mouse_motion(int dx, int dy, int buttons_state)
{
_mouse_handler->on_mouse_motion(dx, dy, buttons_state);
}
void InputsChannel::on_mouse_motion(int dx, int dy, int buttons_state)
{
Lock lock(_motion_lock);
_mouse_buttons_state = buttons_state;
_mouse_dx += dx;
_mouse_dy += dy;
if (!_active_motion && _motion_count < SPICE_INPUT_MOTION_ACK_BUNCH * 2) {
_active_motion = true;
_motion_count++;
post_message(new MotionMessage(*this));
}
}
void RedScreen::reset_mouse_pos()
{
_window.set_mouse_position(_mouse_anchor_point.x, _mouse_anchor_point.y);
}
void RedWindow::set_mouse_position(int x, int y)
{
XWarpPointer(x_display, None, _win, 0, 0, 0, 0, x + get_origin().x, y + get_origin().y);
}
2.服务器端 spice mouse鼠标的移动信息处理
<1> 按照spice protocal协议解析客户端放送消息
<2>通过VDI接口调用,进入qemu-kvm
static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type,
void *message)
{
case SPICE_MSGC_INPUTS_MOUSE_MOTION: {
SpiceMsgcMouseMotion *mouse_motion = (SpiceMsgcMouseMotion *)buf;
if (++icc->motion_count % SPICE_INPUT_MOTION_ACK_BUNCH == 0 &&
!g_inputs_channel->src_during_migrate) {
red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MOUSE_MOTION_ACK);
icc->motion_count = 0;
}
if (mouse && reds_get_mouse_mode() == SPICE_MOUSE_MODE_SERVER) {
SpiceMouseInterface *sif;
sif = SPICE_CONTAINEROF(mouse->base.sif, SpiceMouseInterface, base);
sif->motion(mouse,
mouse_motion->dx, mouse_motion->dy, 0,
RED_MOUSE_STATE_TO_LOCAL(mouse_motion->buttons_state));
}
break;
}
qemu-kvm 提供VDI接口
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,
};
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));
}
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
{
QEMUPutMouseEntry *entry;
QEMUPutMouseEvent *mouse_event;
void *mouse_event_opaque;
int width;
if (QTAILQ_EMPTY(&mouse_handlers)) {
return;
}
entry = QTAILQ_FIRST(&mouse_handlers);
mouse_event = entry->qemu_put_mouse_event;
mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
if (mouse_event) {
if (graphic_rotate) {
if (entry->qemu_put_mouse_event_absolute)
width = 0x7fff;
else
width = graphic_width - 1;
mouse_event(mouse_event_opaque,
width - dy, dx, dz, buttons_state);
} else
mouse_event(mouse_event_opaque,
dx, dy, dz, buttons_state);
}
}
3.qemu-kvm 提供ps2 mouse鼠标硬件的模拟
<1>VDI接口是虚拟设备的接口
<2>该接口操从虚拟设备,从而影响客户机操作系统鼠标设备驱动。
qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
qemu_add_mouse_event_handler(usb_pointer_event, s,
static void ps2_mouse_event(void *opaque,
int dx, int dy, int dz, int buttons_state)
{
PS2MouseState *s = opaque;
/* check if deltas are recorded when disabled */
if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
return;
s->mouse_dx += dx;
s->mouse_dy -= dy;
s->mouse_dz += dz;
/* XXX: SDL sometimes generates nul events: we delete them */
if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
s->mouse_buttons == buttons_state)
return;
s->mouse_buttons = buttons_state;
if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
(s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
for(;;) {
/* if not remote, send event. Multiple events are sent if
too big deltas */
ps2_mouse_send_packet(s);
if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
break;
}
}
}
http://blog.csdn.net/zhuriyuxiao/article/details/8845122
阅读(3194) | 评论(0) | 转发(0) |