diff options
author | Yaniv Kamay <ykamay@redhat.com> | 2009-09-19 21:25:46 +0300 |
---|---|---|
committer | Yaniv Kamay <ykamay@redhat.com> | 2009-10-14 15:06:41 +0200 |
commit | c1b79eb035fa158fb2ac3bc8e559809611070016 (patch) | |
tree | 3348dd749a700dedf87c9b16fe8be77c62928df8 /client/inputs_channel.cpp | |
download | spice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.gz spice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.xz spice-c1b79eb035fa158fb2ac3bc8e559809611070016.zip |
fresh start
Diffstat (limited to 'client/inputs_channel.cpp')
-rw-r--r-- | client/inputs_channel.cpp | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/client/inputs_channel.cpp b/client/inputs_channel.cpp new file mode 100644 index 00000000..8035bfb3 --- /dev/null +++ b/client/inputs_channel.cpp @@ -0,0 +1,360 @@ +/* + 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 responce(Application& application) + { + application.set_inputs_handler(_channel); + } + +private: + InputsChannel& _channel; +}; + +class KeyModifiersEvent: public Event { +public: + KeyModifiersEvent(InputsChannel& channel) : _channel (channel) {} + + virtual void responce(Application& application) + { + 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_responce(Application& application) + { + application.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; +} + |