spice/server/cursor-channel.cpp
Frediano Ziglio 1d4fb2fee7 red-parse-qxl: Use a base reference class for RedCursorCmd
Don't code manually reference counting for this structure

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Victor Toso <victortoso@redhat.com>
2021-08-04 13:01:05 +01:00

288 lines
8.7 KiB
C++

/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <glib.h>
#include <common/generated_server_marshallers.h>
#include "common-graphics-channel.h"
#include "cursor-channel.h"
#include "cursor-channel-client.h"
#include "reds.h"
struct RedCursorPipeItem: public RedPipeItemNum<RED_PIPE_ITEM_TYPE_CURSOR> {
explicit RedCursorPipeItem(const red::shared_ptr<const RedCursorCmd>& cmd);
red::shared_ptr<const RedCursorCmd> red_cursor;
};
RedCursorPipeItem::RedCursorPipeItem(const red::shared_ptr<const RedCursorCmd>& cmd):
red_cursor(cmd)
{
}
static void cursor_fill(CursorChannelClient *ccc, RedCursorPipeItem *cursor,
SpiceCursor *red_cursor, SpiceMarshaller *m)
{
if (!cursor) {
red_cursor->flags = SPICE_CURSOR_FLAGS_NONE;
return;
}
auto cursor_cmd = cursor->red_cursor.get();
*red_cursor = cursor_cmd->u.set.shape;
if (red_cursor->header.unique) {
if (ccc->cache_find(red_cursor->header.unique)) {
red_cursor->flags |= SPICE_CURSOR_FLAGS_FROM_CACHE;
return;
}
if (ccc->cache_add(red_cursor->header.unique, 1)) {
red_cursor->flags |= SPICE_CURSOR_FLAGS_CACHE_ME;
}
}
if (red_cursor->data_size) {
SpiceMarshaller *m2 = spice_marshaller_get_submarshaller(m);
cursor->add_to_marshaller(m2, red_cursor->data, red_cursor->data_size);
}
}
static void red_marshall_cursor_init(CursorChannelClient *ccc, SpiceMarshaller *base_marshaller)
{
spice_assert(ccc);
CursorChannel *cursor_channel;
SpiceMsgCursorInit msg;
cursor_channel = ccc->get_channel();
ccc->init_send_data(SPICE_MSG_CURSOR_INIT);
msg.visible = cursor_channel->cursor_visible;
msg.position = cursor_channel->cursor_position;
msg.trail_length = cursor_channel->cursor_trail_length;
msg.trail_frequency = cursor_channel->cursor_trail_frequency;
cursor_fill(ccc, cursor_channel->item.get(), &msg.cursor, base_marshaller);
spice_marshall_msg_cursor_init(base_marshaller, &msg);
}
static void red_marshall_cursor(CursorChannelClient *ccc,
SpiceMarshaller *m,
RedCursorPipeItem *cursor_pipe_item)
{
CursorChannel *cursor_channel = ccc->get_channel();
RedCursorPipeItem *item = cursor_pipe_item;
spice_return_if_fail(cursor_channel);
auto cmd = item->red_cursor.get();
switch (cmd->type) {
case QXL_CURSOR_MOVE:
{
SpiceMsgCursorMove cursor_move;
ccc->init_send_data(SPICE_MSG_CURSOR_MOVE);
cursor_move.position = cmd->u.position;
spice_marshall_msg_cursor_move(m, &cursor_move);
break;
}
case QXL_CURSOR_SET:
{
SpiceMsgCursorSet cursor_set;
ccc->init_send_data(SPICE_MSG_CURSOR_SET);
cursor_set.position = cmd->u.set.position;
cursor_set.visible = cursor_channel->cursor_visible;
cursor_fill(ccc, item, &cursor_set.cursor, m);
spice_marshall_msg_cursor_set(m, &cursor_set);
break;
}
case QXL_CURSOR_HIDE:
ccc->init_send_data(SPICE_MSG_CURSOR_HIDE);
break;
case QXL_CURSOR_TRAIL:
{
SpiceMsgCursorTrail cursor_trail;
ccc->init_send_data(SPICE_MSG_CURSOR_TRAIL);
cursor_trail.length = cmd->u.trail.length;
cursor_trail.frequency = cmd->u.trail.frequency;
spice_marshall_msg_cursor_trail(m, &cursor_trail);
}
break;
default:
spice_error("bad cursor command %d", cmd->type);
}
}
static inline void red_marshall_inval(RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
RedCachePipeItem *cache_item)
{
rcc->init_send_data(SPICE_MSG_CURSOR_INVAL_ONE);
spice_marshall_msg_cursor_inval_one(base_marshaller, &cache_item->inval_one);
}
void CursorChannelClient::send_item(RedPipeItem *pipe_item)
{
SpiceMarshaller *m = get_marshaller();
CursorChannelClient *ccc = this;
switch (pipe_item->type) {
case RED_PIPE_ITEM_TYPE_CURSOR:
red_marshall_cursor(ccc, m, static_cast<RedCursorPipeItem*>(pipe_item));
break;
case RED_PIPE_ITEM_TYPE_INVAL_ONE:
red_marshall_inval(this, m, static_cast<RedCachePipeItem*>(pipe_item));
break;
case RED_PIPE_ITEM_TYPE_CURSOR_INIT:
reset_cursor_cache();
red_marshall_cursor_init(this, m);
break;
case RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
reset_cursor_cache();
init_send_data(SPICE_MSG_CURSOR_INVAL_ALL);
break;
default:
spice_error("invalid pipe item type");
}
begin_send_message();
}
red::shared_ptr<CursorChannel>
cursor_channel_new(RedsState *server, int id,
SpiceCoreInterfaceInternal *core,
Dispatcher *dispatcher)
{
spice_debug("create cursor channel");
return red::make_shared<CursorChannel>(server, id, core, dispatcher);
}
void CursorChannel::process_cmd(red::shared_ptr<const RedCursorCmd> &&cursor_cmd)
{
bool cursor_show = false;
spice_return_if_fail(cursor_cmd);
auto cursor_pipe_item = red::make_shared<RedCursorPipeItem>(cursor_cmd);
switch (cursor_cmd->type) {
case QXL_CURSOR_SET:
cursor_visible = !!cursor_cmd->u.set.visible;
item = cursor_pipe_item;
break;
case QXL_CURSOR_MOVE:
cursor_show = !cursor_visible;
cursor_visible = true;
cursor_position = cursor_cmd->u.position;
break;
case QXL_CURSOR_HIDE:
cursor_visible = false;
break;
case QXL_CURSOR_TRAIL:
cursor_trail_length = cursor_cmd->u.trail.length;
cursor_trail_frequency = cursor_cmd->u.trail.frequency;
break;
default:
spice_warning("invalid cursor command %u", cursor_cmd->type);
return;
}
if (is_connected() &&
(mouse_mode == SPICE_MOUSE_MODE_SERVER
|| cursor_cmd->type != QXL_CURSOR_MOVE
|| cursor_show)) {
pipes_add(cursor_pipe_item);
}
}
void CursorChannel::reset()
{
item.reset();
cursor_visible = true;
cursor_position.x = cursor_position.y = 0;
cursor_trail_length = cursor_trail_frequency = 0;
if (is_connected()) {
pipes_add_type(RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
if (!get_during_target_migrate()) {
pipes_add_empty_msg(SPICE_MSG_CURSOR_RESET);
}
wait_all_sent(COMMON_CLIENT_TIMEOUT);
}
}
static void cursor_channel_init_client(CursorChannel *cursor, CursorChannelClient *client)
{
spice_return_if_fail(cursor);
if (!cursor->is_connected()
|| cursor->get_during_target_migrate()) {
spice_debug("during_target_migrate: skip init");
return;
}
if (client)
client->pipe_add_type(RED_PIPE_ITEM_TYPE_CURSOR_INIT);
else
cursor->pipes_add_type(RED_PIPE_ITEM_TYPE_CURSOR_INIT);
}
void CursorChannel::do_init()
{
cursor_channel_init_client(this, nullptr);
}
void CursorChannel::set_mouse_mode(uint32_t mode)
{
mouse_mode = mode;
}
/**
* Connect a new client to CursorChannel.
*/
void CursorChannel::on_connect(RedClient *client, RedStream *stream, int migration,
RedChannelCapabilities *caps)
{
CursorChannelClient *ccc;
spice_debug("add cursor channel client");
ccc = cursor_channel_client_new(this, client, stream,
migration,
caps);
if (ccc == nullptr) {
return;
}
ccc->ack_zero_messages_window();
ccc->push_set_ack();
cursor_channel_init_client(this, ccc);
}
CursorChannel::~CursorChannel() = default;
CursorChannel::CursorChannel(RedsState *reds, uint32_t id,
SpiceCoreInterfaceInternal *core, Dispatcher *dispatcher):
CommonGraphicsChannel(reds, SPICE_CHANNEL_CURSOR, id, RedChannel::HandleAcks, core, dispatcher)
{
reds_register_channel(reds, this);
}