mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-26 14:41:25 +00:00
The process loop is responsible for: 1) waiting for events 2) timers 3) events queue for actions that should be performed in the context of the thread and are pushed from other threads. The benefits: 1) remove duplicity: till now, there was one implementaion of events loop for the channels and another one for the main thread. 2) timers can be executed on each thread and not only on the main thread. 3) events can be pushed to each thread and not only to the main thread. In this commit, only the main thread was modified to use the new process loop.
361 lines
10 KiB
C++
361 lines
10 KiB
C++
/*
|
|
Copyright (C) 2009 Red Hat, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of
|
|
the License, or (at your option) any later version.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "inputs_channel.h"
|
|
#include "utils.h"
|
|
#include "debug.h"
|
|
#include "red_client.h"
|
|
#include "application.h"
|
|
|
|
#define SYNC_REMOTH_MODIFIRES
|
|
|
|
class SetInputsHandlerEvent: public Event {
|
|
public:
|
|
SetInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {}
|
|
|
|
virtual void response(AbstractProcessLoop& events_loop)
|
|
{
|
|
static_cast<Application*>(events_loop.get_owner())->set_inputs_handler(_channel);
|
|
}
|
|
|
|
private:
|
|
InputsChannel& _channel;
|
|
};
|
|
|
|
class KeyModifiersEvent: public Event {
|
|
public:
|
|
KeyModifiersEvent(InputsChannel& channel) : _channel (channel) {}
|
|
|
|
virtual void response(AbstractProcessLoop& events_loop)
|
|
{
|
|
Lock lock(_channel._update_modifiers_lock);
|
|
_channel._active_modifiers_event = false;
|
|
_channel.set_local_modifiers();
|
|
}
|
|
|
|
private:
|
|
InputsChannel& _channel;
|
|
};
|
|
|
|
class RemoveInputsHandlerEvent: public SyncEvent {
|
|
public:
|
|
RemoveInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {}
|
|
|
|
virtual void do_response(AbstractProcessLoop& events_loop)
|
|
{
|
|
static_cast<Application*>(events_loop.get_owner())->remove_inputs_handler(_channel);
|
|
}
|
|
|
|
private:
|
|
InputsChannel& _channel;
|
|
};
|
|
|
|
class MotionMessage: public RedChannel::OutMessage, public RedPeer::OutMessage {
|
|
public:
|
|
MotionMessage(InputsChannel& channel);
|
|
virtual RedPeer::OutMessage& peer_message();
|
|
virtual void release();
|
|
|
|
private:
|
|
InputsChannel& _channel;
|
|
};
|
|
|
|
MotionMessage::MotionMessage(InputsChannel& channel)
|
|
: RedChannel::OutMessage()
|
|
, RedPeer::OutMessage(REDC_INPUTS_MOUSE_MOTION, sizeof(RedcMouseMotion))
|
|
, _channel (channel)
|
|
{
|
|
}
|
|
|
|
void MotionMessage::release()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
RedPeer::OutMessage& MotionMessage::peer_message()
|
|
{
|
|
_channel.set_motion_event(*(RedcMouseMotion*)data());
|
|
return *this;
|
|
}
|
|
|
|
class PositionMessage: public RedChannel::OutMessage, public RedPeer::OutMessage {
|
|
public:
|
|
PositionMessage(InputsChannel& channel);
|
|
virtual RedPeer::OutMessage& peer_message();
|
|
virtual void release();
|
|
|
|
private:
|
|
InputsChannel& _channel;
|
|
};
|
|
|
|
PositionMessage::PositionMessage(InputsChannel& channel)
|
|
: RedChannel::OutMessage()
|
|
, RedPeer::OutMessage(REDC_INPUTS_MOUSE_POSITION, sizeof(RedcMousePosition))
|
|
, _channel (channel)
|
|
{
|
|
}
|
|
|
|
void PositionMessage::release()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
RedPeer::OutMessage& PositionMessage::peer_message()
|
|
{
|
|
_channel.set_position_event(*(RedcMousePosition*)data());
|
|
return *this;
|
|
}
|
|
|
|
class InputsMessHandler: public MessageHandlerImp<InputsChannel, RED_INPUTS_MESSAGES_END> {
|
|
public:
|
|
InputsMessHandler(InputsChannel& channel)
|
|
: MessageHandlerImp<InputsChannel, RED_INPUTS_MESSAGES_END>(channel) {}
|
|
};
|
|
|
|
InputsChannel::InputsChannel(RedClient& client, uint32_t id)
|
|
: RedChannel(client, RED_CHANNEL_INPUTS, id, new InputsMessHandler(*this))
|
|
, _mouse_buttons_state (0)
|
|
, _mouse_dx (0)
|
|
, _mouse_dy (0)
|
|
, _mouse_x (~0)
|
|
, _mouse_y (~0)
|
|
, _display_id (-1)
|
|
, _active_motion (false)
|
|
, _motion_count (0)
|
|
, _active_modifiers_event (false)
|
|
{
|
|
InputsMessHandler* handler = static_cast<InputsMessHandler*>(get_message_handler());
|
|
handler->set_handler(RED_MIGRATE, &InputsChannel::handle_migrate, 0);
|
|
handler->set_handler(RED_SET_ACK, &InputsChannel::handle_set_ack, sizeof(RedSetAck));
|
|
handler->set_handler(RED_PING, &InputsChannel::handle_ping, sizeof(RedPing));
|
|
handler->set_handler(RED_WAIT_FOR_CHANNELS, &InputsChannel::handle_wait_for_channels,
|
|
sizeof(RedWaitForChannels));
|
|
handler->set_handler(RED_DISCONNECTING, &InputsChannel::handle_disconnect,
|
|
sizeof(RedDisconnect));
|
|
handler->set_handler(RED_NOTIFY, &InputsChannel::handle_notify, sizeof(RedNotify));
|
|
|
|
handler->set_handler(RED_INPUTS_INIT, &InputsChannel::handle_init, sizeof(RedInputsInit));
|
|
handler->set_handler(RED_INPUTS_KEY_MODIFAIERS, &InputsChannel::handle_modifaiers,
|
|
sizeof(RedKeyModifiers));
|
|
handler->set_handler(RED_INPUTS_MOUSE_MOTION_ACK, &InputsChannel::handle_motion_ack, 0);
|
|
}
|
|
|
|
InputsChannel::~InputsChannel()
|
|
{
|
|
}
|
|
|
|
void InputsChannel::on_connect()
|
|
{
|
|
_motion_count = _mouse_dx = _mouse_dy = _mouse_buttons_state = _modifiers = 0;
|
|
_mouse_x = _mouse_y = ~0;
|
|
_display_id = -1;
|
|
}
|
|
|
|
void InputsChannel::on_disconnect()
|
|
{
|
|
AutoRef<RemoveInputsHandlerEvent> remove_handler_event(new RemoveInputsHandlerEvent(*this));
|
|
get_client().push_event(*remove_handler_event);
|
|
(*remove_handler_event)->wait();
|
|
}
|
|
|
|
void InputsChannel::handle_init(RedPeer::InMessage* message)
|
|
{
|
|
RedInputsInit* init = (RedInputsInit*)message->data();
|
|
_modifiers = init->keyboard_modifiers;
|
|
AutoRef<SetInputsHandlerEvent> set_handler_event(new SetInputsHandlerEvent(*this));
|
|
get_client().push_event(*set_handler_event);
|
|
}
|
|
|
|
void InputsChannel::handle_modifaiers(RedPeer::InMessage* message)
|
|
{
|
|
RedKeyModifiers* init = (RedKeyModifiers*)message->data();
|
|
_modifiers = init->modifiers;
|
|
Lock lock(_update_modifiers_lock);
|
|
if (_active_modifiers_event) {
|
|
return;
|
|
}
|
|
_active_modifiers_event = true;
|
|
AutoRef<KeyModifiersEvent> modifiers_event(new KeyModifiersEvent(*this));
|
|
get_client().push_event(*modifiers_event);
|
|
}
|
|
|
|
void InputsChannel::handle_motion_ack(RedPeer::InMessage* message)
|
|
{
|
|
Lock lock(_motion_lock);
|
|
if (_motion_count < RED_MOTION_ACK_BUNCH) {
|
|
LOG_WARN("invalid motion count");
|
|
_motion_count = 0;
|
|
} else {
|
|
_motion_count -= RED_MOTION_ACK_BUNCH;
|
|
}
|
|
if (!_active_motion && (_mouse_dx || _mouse_dy || _display_id != -1)) {
|
|
_active_motion = true;
|
|
_motion_count++;
|
|
switch (get_client().get_mouse_mode()) {
|
|
case RED_MOUSE_MODE_CLIENT:
|
|
post_message(new PositionMessage(*this));
|
|
break;
|
|
case RED_MOUSE_MODE_SERVER:
|
|
post_message(new MotionMessage(*this));
|
|
break;
|
|
default:
|
|
THROW("invalid mouse mode");
|
|
}
|
|
}
|
|
}
|
|
|
|
void InputsChannel::set_motion_event(RedcMouseMotion& motion)
|
|
{
|
|
Lock lock(_motion_lock);
|
|
motion.buttons_state = _mouse_buttons_state;
|
|
motion.dx = _mouse_dx;
|
|
motion.dy = _mouse_dy;
|
|
_mouse_dx = _mouse_dy = 0;
|
|
_active_motion = false;
|
|
}
|
|
|
|
void InputsChannel::set_position_event(RedcMousePosition& position)
|
|
{
|
|
Lock lock(_motion_lock);
|
|
position.buttons_state = _mouse_buttons_state;
|
|
position.x = _mouse_x;
|
|
position.y = _mouse_y;
|
|
position.display_id = _display_id;
|
|
_mouse_x = _mouse_y = ~0;
|
|
_display_id = -1;
|
|
_active_motion = false;
|
|
}
|
|
|
|
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 < RED_MOTION_ACK_BUNCH * 2) {
|
|
_active_motion = true;
|
|
_motion_count++;
|
|
post_message(new MotionMessage(*this));
|
|
}
|
|
}
|
|
|
|
void InputsChannel::on_mouse_position(int x, int y, int buttons_state, int display_id)
|
|
{
|
|
Lock lock(_motion_lock);
|
|
_mouse_buttons_state = buttons_state;
|
|
_mouse_x = x;
|
|
_mouse_y = y;
|
|
_display_id = display_id;
|
|
if (!_active_motion && _motion_count < RED_MOTION_ACK_BUNCH * 2) {
|
|
_active_motion = true;
|
|
_motion_count++;
|
|
post_message(new PositionMessage(*this));
|
|
}
|
|
}
|
|
|
|
void InputsChannel::on_migrate()
|
|
{
|
|
_motion_count = _active_motion ? 1 : 0;
|
|
}
|
|
|
|
void InputsChannel::on_mouse_down(int button, int buttons_state)
|
|
{
|
|
Message* message;
|
|
|
|
message = new Message(REDC_INPUTS_MOUSE_PRESS, sizeof(RedcMouseRelease));
|
|
RedcMousePress* event = (RedcMousePress*)message->data();
|
|
event->button = button;
|
|
event->buttons_state = buttons_state;
|
|
post_message(message);
|
|
}
|
|
|
|
void InputsChannel::on_mouse_up(int button, int buttons_state)
|
|
{
|
|
Message* message;
|
|
|
|
message = new Message(REDC_INPUTS_MOUSE_RELEASE, sizeof(RedcMouseRelease));
|
|
RedcMouseRelease* event = (RedcMouseRelease*)message->data();
|
|
event->button = button;
|
|
event->buttons_state = buttons_state;
|
|
post_message(message);
|
|
}
|
|
|
|
void InputsChannel::on_key_down(uint32_t scan_code)
|
|
{
|
|
Message* message = new Message(REDC_INPUTS_KEY_DOWN, sizeof(RedcKeyDown));
|
|
RedcKeyDown* event = (RedcKeyDown*)message->data();
|
|
event->code = scan_code;
|
|
post_message(message);
|
|
}
|
|
|
|
void InputsChannel::on_key_up(uint32_t scan_code)
|
|
{
|
|
Message* message = new Message(REDC_INPUTS_KEY_UP, sizeof(RedcKeyUp));
|
|
RedcKeyUp* event = (RedcKeyUp*)message->data();
|
|
event->code = scan_code;
|
|
post_message(message);
|
|
}
|
|
|
|
void InputsChannel::set_local_modifiers()
|
|
{
|
|
unsigned int modifiers = 0;
|
|
|
|
if (_modifiers & RED_SCROLL_LOCK_MODIFIER) {
|
|
modifiers |= Platform::SCROLL_LOCK_MODIFIER;
|
|
}
|
|
|
|
if (_modifiers & RED_NUM_LOCK_MODIFIER) {
|
|
modifiers |= Platform::NUM_LOCK_MODIFIER;
|
|
}
|
|
|
|
if (_modifiers & RED_CAPS_LOCK_MODIFIER) {
|
|
modifiers |= Platform::CAPS_LOCK_MODIFIER;
|
|
}
|
|
|
|
Platform::set_keyboard_modifiers(_modifiers);
|
|
}
|
|
|
|
void InputsChannel::on_focus_in()
|
|
{
|
|
#ifdef SYNC_REMOTH_MODIFIRES
|
|
Message* message = new Message(REDC_INPUTS_KEY_MODIFAIERS, sizeof(RedcKeyDown));
|
|
RedcKeyModifiers* modifiers = (RedcKeyModifiers*)message->data();
|
|
modifiers->modifiers = Platform::get_keyboard_modifiers();
|
|
post_message(message);
|
|
#else
|
|
set_local_modifiers();
|
|
#endif
|
|
}
|
|
|
|
class InputsFactory: public ChannelFactory {
|
|
public:
|
|
InputsFactory() : ChannelFactory(RED_CHANNEL_INPUTS) {}
|
|
virtual RedChannel* construct(RedClient& client, uint32_t id)
|
|
{
|
|
return new InputsChannel(client, id);
|
|
}
|
|
};
|
|
|
|
static InputsFactory factory;
|
|
|
|
ChannelFactory& InputsChannel::Factory()
|
|
{
|
|
return factory;
|
|
}
|
|
|