summaryrefslogtreecommitdiffstats
path: root/client/inputs_channel.cpp
diff options
context:
space:
mode:
authorYaniv Kamay <ykamay@redhat.com>2009-09-19 21:25:46 +0300
committerYaniv Kamay <ykamay@redhat.com>2009-10-14 15:06:41 +0200
commitc1b79eb035fa158fb2ac3bc8e559809611070016 (patch)
tree3348dd749a700dedf87c9b16fe8be77c62928df8 /client/inputs_channel.cpp
downloadspice-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.cpp360
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;
+}
+