summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaniv Kamay <ykamay@redhat.com>2009-11-16 17:50:16 +0200
committerYaniv Kamay <ykamay@redhat.com>2009-11-30 18:03:35 +0200
commit3b51087b3656b111886c7397d0ddd499a96f9e2d (patch)
tree21cdb7b0dc282062bd811f65ee295a7074b58275
parenta70110c4e50aad99de7a844bb78eb868768e7841 (diff)
downloadspice-3b51087b3656b111886c7397d0ddd499a96f9e2d.tar.gz
spice-3b51087b3656b111886c7397d0ddd499a96f9e2d.tar.xz
spice-3b51087b3656b111886c7397d0ddd499a96f9e2d.zip
client: interactive screen layer
-rw-r--r--client/application.cpp37
-rw-r--r--client/application.h3
-rw-r--r--client/cursor_channel.cpp370
-rw-r--r--client/cursor_channel.h28
-rw-r--r--client/display_channel.cpp212
-rw-r--r--client/display_channel.h28
-rw-r--r--client/inputs_channel.cpp35
-rw-r--r--client/inputs_channel.h5
-rw-r--r--client/inputs_handler.h1
-rw-r--r--client/red_client.cpp62
-rw-r--r--client/red_client.h7
-rw-r--r--client/red_window.h16
-rw-r--r--client/screen.cpp302
-rw-r--r--client/screen.h47
-rw-r--r--client/screen_layer.cpp19
-rw-r--r--client/screen_layer.h9
-rw-r--r--client/windows/red_window.cpp49
-rw-r--r--client/x11/red_window.cpp18
18 files changed, 865 insertions, 383 deletions
diff --git a/client/application.cpp b/client/application.cpp
index db930400..a49576e2 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -358,6 +358,22 @@ void Application::remove_inputs_handler(InputsHandler& handler)
_inputs_handler = &default_inputs_handler;
}
+void Application::capture_mouse()
+{
+ if (!_active_screen) {
+ return;
+ }
+ _active_screen->capture_mouse();
+}
+
+void Application::release_mouse_capture()
+{
+ if (!_active_screen || !_active_screen->is_mouse_captured()) {
+ return;
+ }
+ _active_screen->relase_mouse();
+}
+
void Application::abort()
{
Platform::set_event_listener(NULL);
@@ -402,10 +418,10 @@ RedScreen* Application::find_screen(int id)
bool Application::release_capture()
{
unpress_all();
- if (!_active_screen || !_active_screen->is_captured()) {
+ if (!_active_screen || !_active_screen->is_mouse_captured()) {
return false;
}
- _active_screen->relase_inputs();
+ _active_screen->relase_mouse();
return true;
}
@@ -455,7 +471,7 @@ RedScreen* Application::get_screen(int id)
if (capture) {
_main_screen->activate();
- _main_screen->capture_inputs();
+ _main_screen->capture_mouse();
}
} else if (id != 0) {
screen->show(false, _main_screen);
@@ -489,7 +505,7 @@ void Application::on_screen_destroyed(int id, bool was_captured)
position_screens();
if (capture) {
_main_screen->activate();
- _main_screen->capture_inputs();
+ _main_screen->capture_mouse();
}
}
}
@@ -499,11 +515,6 @@ void Application::on_mouse_motion(int dx, int dy, int buttons_state)
_inputs_handler->on_mouse_motion(dx, dy, buttons_state);
}
-void Application::on_mouse_position(int x, int y, int buttons_state, int display_id)
-{
- _inputs_handler->on_mouse_position(x, y, buttons_state, display_id);
-}
-
void Application::on_mouse_down(int button, int buttons_state)
{
_inputs_handler->on_mouse_down(button, buttons_state);
@@ -1084,7 +1095,7 @@ bool Application::rearrange_monitors(RedScreen& screen)
if (capture && _main_screen != &screen) {
capture = false;
_main_screen->activate();
- _main_screen->capture_inputs();
+ _main_screen->capture_mouse();
}
return capture;
}
@@ -1194,14 +1205,16 @@ void Application::enter_full_screen()
{
LOG_INFO("");
_changing_screens = true;
- release_capture();
+ bool capture = release_capture();
assign_monitors();
hide();
prepare_monitors();
position_screens();
show_full_screen();
_main_screen->activate();
- _main_screen->capture_inputs();
+ if (capture) {
+ _main_screen->capture_mouse();
+ }
_changing_screens = false;
_full_screen = true;
}
diff --git a/client/application.h b/client/application.h
index c576dba6..90d2fa33 100644
--- a/client/application.h
+++ b/client/application.h
@@ -121,12 +121,13 @@ public:
void set_inputs_handler(InputsHandler& handler);
void remove_inputs_handler(InputsHandler& handler);
+ void capture_mouse();
+ void release_mouse_capture();
RedScreen* find_screen(int id);
RedScreen* get_screen(int id);
void on_screen_destroyed(int id, bool was_captured);
void on_mouse_motion(int dx, int dy, int buttons_state);
- void on_mouse_position(int x, int y, int buttons_state, int display_id);
void on_mouse_down(int button, int buttons_state);
void on_mouse_up(int button, int buttons_state);
void on_key_down(RedKey key);
diff --git a/client/cursor_channel.cpp b/client/cursor_channel.cpp
index fd8761a6..8a8fc658 100644
--- a/client/cursor_channel.cpp
+++ b/client/cursor_channel.cpp
@@ -17,6 +17,7 @@
#include "common.h"
#include "cursor_channel.h"
+#include "display_channel.h"
#include "cursor.h"
#include "red_client.h"
#include "application.h"
@@ -283,165 +284,66 @@ private:
uint32_t* _palette;
};
-class CursorSetEvent: public Event {
+class AttachDispayEvent: public Event {
public:
- CursorSetEvent(CursorChannel& channel, CursorData *cursor, int x, int y, bool visable)
+ AttachDispayEvent(CursorChannel& channel)
: _channel (channel)
- , _cursor (cursor->ref())
- , _x (x)
- , _y (y)
- , _visible (visable)
{
}
- void create_cursor()
- {
- CursorData *cursor = *_cursor;
- CursorOpaque* native_cursor = cursor->get_opaque();
-
- if (native_cursor) {
- return;
- }
-
- switch (cursor->header().type) {
- case CURSOR_TYPE_ALPHA:
- native_cursor = new AlphaCursor(cursor->header(), cursor->data());
- break;
- case CURSOR_TYPE_COLOR32:
- native_cursor = new ColorCursor32(cursor->header(), cursor->data());
- break;
- case CURSOR_TYPE_MONO:
- native_cursor = new MonoCursor(cursor->header(), cursor->data());
- break;
- case CURSOR_TYPE_COLOR4:
- native_cursor = new ColorCursor4(cursor->header(), cursor->data());
- break;
- case CURSOR_TYPE_COLOR8:
- native_cursor = new UnsupportedCursor(cursor->header());
- break;
- case CURSOR_TYPE_COLOR16:
- native_cursor = new ColorCursor16(cursor->header(), cursor->data());
- break;
- case CURSOR_TYPE_COLOR24:
- native_cursor = new UnsupportedCursor(cursor->header());
- break;
- default:
- THROW("invalid curosr type");
+ class UpdateDisplayChannel: public ForEachChannelFunc {
+ public:
+ UpdateDisplayChannel(CursorChannel& channel)
+ : _channel (channel)
+ {
}
- cursor->set_opaque(native_cursor);
- }
-
- virtual void response(AbstractProcessLoop& events_loop)
- {
- CursorData *cursor = *_cursor;
- create_cursor();
- Lock lock(_channel._update_lock);
- _channel._hot_pos.x = _x;
- _channel._hot_pos.y = _y;
- _channel._cursor_visible = _visible;
- _channel._cursor_rect.left = _x - cursor->header().hot_spot_x;
- _channel._cursor_rect.right = _channel._cursor_rect.left + cursor->header().width;
- _channel._cursor_rect.top = _y - cursor->header().hot_spot_y;
- _channel._cursor_rect.bottom = _channel._cursor_rect.top + cursor->header().height;
-
- if (static_cast<Application*>(events_loop.get_owner())->get_mouse_mode() ==
- RED_MOUSE_MODE_CLIENT) {
- RedScreen* screen = _channel.screen();
- ASSERT(screen);
- screen->set_cursor(_visible ? cursor : NULL);
- } else {
- if (_visible) {
- _channel.set_rect_area(_channel._cursor_rect);
- } else {
- _channel.clear_area();
+ virtual bool operator() (RedChannel& channel)
+ {
+ if (channel.get_type() != RED_CHANNEL_DISPLAY ||
+ channel.get_id() != _channel.get_id()) {
+ return true;
}
- }
- if (_channel._cursor) {
- _channel._cursor->unref();
+ _channel.attach_display(&static_cast<DisplayChannel&>(channel));
+ return false;
}
- _channel._cursor = cursor->ref();
+ private:
+ CursorChannel& _channel;
+ };
+
+ virtual void response(AbstractProcessLoop& events_loop)
+ {
+ UpdateDisplayChannel func(_channel);
+ _channel.get_client().for_each_channel(func);
}
private:
CursorChannel& _channel;
- AutoRef<CursorData> _cursor;
- int _x;
- int _y;
- bool _visible;
};
-class CursorMoveEvent: public Event {
+class CursorUpdateEvent: public Event {
public:
- CursorMoveEvent(CursorChannel& channel, int x, int y)
+ CursorUpdateEvent(CursorChannel& channel)
: _channel (channel)
- , _x (x)
- , _y (y)
{
}
virtual void response(AbstractProcessLoop& events_loop)
{
- _channel._cursor_visible = true;
- if (static_cast<Application*>(events_loop.get_owner())->get_mouse_mode() ==
- RED_MOUSE_MODE_CLIENT) {
- RedScreen* screen = _channel.screen();
- ASSERT(screen);
- screen->set_cursor(_channel._cursor);
- } else {
- Lock lock(_channel._update_lock);
- int dx = _x - _channel._hot_pos.x;
- int dy = _y - _channel._hot_pos.y;
- _channel._hot_pos.x += dx;
- _channel._hot_pos.y += dy;
- _channel._cursor_rect.left += dx;
- _channel._cursor_rect.right += dx;
- _channel._cursor_rect.top += dy;
- _channel._cursor_rect.bottom += dy;
- lock.unlock();
- _channel.set_rect_area(_channel._cursor_rect);
+ DisplayChannel* display_channel = _channel._display_channel;
+ if (!display_channel) {
+ return;
}
- }
-
-private:
- CursorChannel& _channel;
- int _x;
- int _y;
-};
-class CursorHideEvent: public Event {
-public:
- CursorHideEvent(CursorChannel& channel): _channel (channel) {}
- virtual void response(AbstractProcessLoop& events_loop)
- {
- _channel._cursor_visible = false;
- if (static_cast<Application*>(events_loop.get_owner())->get_mouse_mode() ==
- RED_MOUSE_MODE_CLIENT) {
- RedScreen* screen = _channel.screen();
- ASSERT(screen);
- screen->set_cursor(NULL);
- } else {
- _channel.clear_area();
+ Lock lock(_channel._update_lock);
+ if (_channel._cursor_visible) {
+ display_channel->set_cursor(_channel._cursor);
+ return;
}
- }
-private:
- CursorChannel& _channel;
-};
-
-class CursorRemoveEvent: public Event {
-public:
- CursorRemoveEvent(CursorChannel& channel): _channel (channel) {}
- virtual void response(AbstractProcessLoop& events_loop)
- {
- _channel._cursor_visible = false;
- _channel.clear_area();
- if (_channel._cursor) {
- _channel._cursor->unref();
- _channel._cursor = NULL;
- }
+ display_channel->hide_cursor();
}
private:
@@ -454,51 +356,12 @@ public:
: MessageHandlerImp<CursorChannel, RED_CURSOR_MESSAGES_END>(channel) {}
};
-class CursorModeEvent: public Event {
-public:
- CursorModeEvent(CursorChannel& channel): _channel (channel) {}
-
- virtual void response(AbstractProcessLoop& events_loop)
- {
- RedScreen* screen = _channel.screen();
- if (!screen) {
- return;
- }
- if (static_cast<Application*>(events_loop.get_owner())->get_mouse_mode() ==
- RED_MOUSE_MODE_CLIENT) {
- _channel.clear_area();
- screen->set_cursor(_channel._cursor_visible ? _channel._cursor : NULL);
- } else {
- if (_channel._cursor_visible && _channel._cursor) {
- _channel.set_rect_area(_channel._cursor_rect);
- } else {
- _channel.clear_area();
- }
- }
- screen->relase_inputs();
- }
-
-private:
- CursorChannel& _channel;
-};
-
-CursorModeTrigger::CursorModeTrigger(CursorChannel& channel)
- : _channel (channel)
-{
-}
-
-void CursorModeTrigger::on_event()
-{
- AutoRef<CursorModeEvent> set_event(new CursorModeEvent(_channel));
- _channel.get_client().push_event(*set_event);
-}
-
CursorChannel::CursorChannel(RedClient& client, uint32_t id)
: RedChannel(client, RED_CHANNEL_CURSOR, id, new CursorHandler(*this))
, ScreenLayer(SCREEN_LAYER_CURSOR, false)
, _cursor (NULL)
- , _cursor_trigger (*this)
, _cursor_visible (false)
+ , _display_channel (NULL)
{
CursorHandler* handler = static_cast<CursorHandler*>(get_message_handler());
@@ -523,8 +386,6 @@ CursorChannel::CursorChannel(RedClient& client, uint32_t id)
handler->set_handler(RED_CURSOR_INVAL_ONE, &CursorChannel::handle_inval_one,
sizeof(RedInvalOne));
handler->set_handler(RED_CURSOR_INVAL_ALL, &CursorChannel::handle_inval_all, 0);
-
- get_process_loop().add_trigger(_cursor_trigger);
}
CursorChannel::~CursorChannel()
@@ -534,6 +395,8 @@ CursorChannel::~CursorChannel()
void CursorChannel::on_connect()
{
+ AutoRef<AttachDispayEvent> attach_event(new AttachDispayEvent(*this));
+ get_client().push_event(*attach_event);
}
void CursorChannel::on_disconnect()
@@ -546,15 +409,37 @@ void CursorChannel::on_disconnect()
detach_from_screen(get_client().get_application());
}
+void CursorChannel::update_display_cursor()
+{
+ if (!_display_channel) {
+ return;
+ }
+
+ AutoRef<CursorUpdateEvent> update_event(new CursorUpdateEvent(*this));
+ get_client().push_event(*update_event);
+}
+
void CursorChannel::remove_cursor()
{
- AutoRef<CursorRemoveEvent> event(new CursorRemoveEvent(*this));
- get_client().push_event(*event);
+ Lock lock(_update_lock);
+ _cursor_visible = false;
+ if (_cursor) {
+ _cursor->unref();
+ _cursor = NULL;
+ }
+ lock.unlock();
+ clear_area();
+ update_display_cursor();
}
void CursorChannel::copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc)
{
Lock lock(_update_lock);
+
+ if (!_cursor_visible) {
+ return;
+ }
+
for (int i = 0; i < (int)dest_region.num_rects; i++) {
ASSERT(_cursor && _cursor->get_opaque());
((NaitivCursor*)_cursor->get_opaque())->draw(dest_dc, _cursor_rect.left, _cursor_rect.top,
@@ -562,6 +447,42 @@ void CursorChannel::copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc
}
}
+void CursorChannel::create_native_cursor(CursorData* cursor)
+{
+ CursorOpaque* native_cursor = cursor->get_opaque();
+
+ if (native_cursor) {
+ return;
+ }
+
+ switch (cursor->header().type) {
+ case CURSOR_TYPE_ALPHA:
+ native_cursor = new AlphaCursor(cursor->header(), cursor->data());
+ break;
+ case CURSOR_TYPE_COLOR32:
+ native_cursor = new ColorCursor32(cursor->header(), cursor->data());
+ break;
+ case CURSOR_TYPE_MONO:
+ native_cursor = new MonoCursor(cursor->header(), cursor->data());
+ break;
+ case CURSOR_TYPE_COLOR4:
+ native_cursor = new ColorCursor4(cursor->header(), cursor->data());
+ break;
+ case CURSOR_TYPE_COLOR8:
+ native_cursor = new UnsupportedCursor(cursor->header());
+ break;
+ case CURSOR_TYPE_COLOR16:
+ native_cursor = new ColorCursor16(cursor->header(), cursor->data());
+ break;
+ case CURSOR_TYPE_COLOR24:
+ native_cursor = new UnsupportedCursor(cursor->header());
+ break;
+ default:
+ THROW("invalid curosr type");
+ }
+ cursor->set_opaque(native_cursor);
+}
+
void CursorChannel::set_cursor(RedCursor& red_cursor, int data_size, int x, int y, bool visible)
{
CursorData *cursor;
@@ -582,8 +503,53 @@ void CursorChannel::set_cursor(RedCursor& red_cursor, int data_size, int x, int
}
AutoRef<CursorData> cursor_ref(cursor);
- AutoRef<CursorSetEvent> set_event(new CursorSetEvent(*this, *cursor_ref, x, y, visible));
- get_client().push_event(*set_event);
+ create_native_cursor(cursor);
+
+ Lock lock(_update_lock);
+ _hot_pos.x = x;
+ _hot_pos.y = y;
+ _cursor_visible = visible;
+ _cursor_rect.left = x - cursor->header().hot_spot_x;
+ _cursor_rect.right = _cursor_rect.left + cursor->header().width;
+ _cursor_rect.top = y - cursor->header().hot_spot_y;
+ _cursor_rect.bottom = _cursor_rect.top + cursor->header().height;
+
+ if (_cursor) {
+ _cursor->unref();
+ }
+ _cursor = cursor->ref();
+ lock.unlock();
+
+ update_display_cursor();
+
+ if (get_client().get_mouse_mode() == RED_MOUSE_MODE_SERVER) {
+ if (_cursor_visible) {
+ set_rect_area(_cursor_rect);
+ } else {
+ clear_area();
+ }
+ }
+}
+
+void CursorChannel::attach_display(DisplayChannel* channel)
+{
+ if (_display_channel) {
+ return;
+ }
+
+ _display_channel = channel;
+
+ Lock lock(_update_lock);
+ if (!_cursor_visible) {
+ return;
+ }
+
+ _display_channel->set_cursor(_cursor);
+}
+
+void CursorChannel::detach_display()
+{
+ _display_channel = NULL;
}
void CursorChannel::handle_init(RedPeer::InMessage *message)
@@ -592,7 +558,6 @@ void CursorChannel::handle_init(RedPeer::InMessage *message)
attach_to_screen(get_client().get_application(), get_id());
remove_cursor();
_cursor_cache.clear();
- set_cursor_mode();
set_cursor(init->cursor, message->size() - sizeof(RedCursorInit), init->position.x,
init->position.y, init->visible != 0);
}
@@ -614,15 +579,41 @@ void CursorChannel::handle_cursor_set(RedPeer::InMessage* message)
void CursorChannel::handle_cursor_move(RedPeer::InMessage* message)
{
RedCursorMove* move = (RedCursorMove*)message->data();
- AutoRef<CursorMoveEvent> event(new CursorMoveEvent(*this, move->postition.x,
- move->postition.y));
- get_client().push_event(*event);
+
+ if (!_cursor) {
+ return;
+ }
+
+ Lock lock(_update_lock);
+ _cursor_visible = true;
+ int dx = move->postition.x - _hot_pos.x;
+ int dy = move->postition.y - _hot_pos.y;
+ _hot_pos.x += dx;
+ _hot_pos.y += dy;
+ _cursor_rect.left += dx;
+ _cursor_rect.right += dx;
+ _cursor_rect.top += dy;
+ _cursor_rect.bottom += dy;
+ lock.unlock();
+
+ if (get_client().get_mouse_mode() == RED_MOUSE_MODE_SERVER) {
+ set_rect_area(_cursor_rect);
+ return;
+ }
+
+ update_display_cursor();
}
void CursorChannel::handle_cursor_hide(RedPeer::InMessage* message)
{
- AutoRef<CursorHideEvent> event(new CursorHideEvent(*this));
- get_client().push_event(*event);
+ Lock lock(_update_lock);
+
+ _cursor_visible = false;
+ update_display_cursor();
+
+ if (get_client().get_mouse_mode() == RED_MOUSE_MODE_SERVER) {
+ clear_area();
+ }
}
void CursorChannel::handle_cursor_trail(RedPeer::InMessage* message)
@@ -642,9 +633,18 @@ void CursorChannel::handle_inval_all(RedPeer::InMessage* message)
_cursor_cache.clear();
}
-void CursorChannel::set_cursor_mode()
+void CursorChannel::on_mouse_mode_change()
{
- _cursor_trigger.trigger();
+ Lock lock(_update_lock);
+
+ if (get_client().get_mouse_mode() == RED_MOUSE_MODE_CLIENT) {
+ clear_area();
+ return;
+ }
+
+ if (_cursor_visible) {
+ set_rect_area(_cursor_rect);
+ }
}
class CursorFactory: public ChannelFactory {
diff --git a/client/cursor_channel.h b/client/cursor_channel.h
index 5ac40c10..699d5197 100644
--- a/client/cursor_channel.h
+++ b/client/cursor_channel.h
@@ -25,6 +25,7 @@
class ChannelFactory;
class CursorChannel;
+class DisplayChannel;
class CursorCacheTreat {
public:
@@ -43,28 +44,25 @@ public:
typedef Cache<CursorData, CursorCacheTreat, 1024> CursorCache;
-class CursorModeTrigger: public EventSources::Trigger {
-public:
- CursorModeTrigger(CursorChannel& channel);
- virtual void on_event();
-
-private:
- CursorChannel& _channel;
-};
-
class CursorChannel: public RedChannel, public ScreenLayer {
public:
CursorChannel(RedClient& client, uint32_t id);
virtual ~CursorChannel();
static ChannelFactory& Factory();
- void set_cursor_mode();
+ void on_mouse_mode_change();
+
+ void attach_display(DisplayChannel* channel);
+ void detach_display();
protected:
virtual void on_connect();
virtual void on_disconnect();
private:
+ static void create_native_cursor(CursorData* cursor);
+
+ void update_display_cursor();
void set_cursor(RedCursor& red_cursor, int data_size, int x, int y, bool visible);
void remove_cursor();
@@ -79,21 +77,17 @@ private:
void handle_inval_one(RedPeer::InMessage* message);
void handle_inval_all(RedPeer::InMessage* message);
- friend class CursorSetEvent;
- friend class CursorMoveEvent;
- friend class CursorHideEvent;
- friend class CursorRemoveEvent;
- friend class CursorModeTrigger;
- friend class CursorModeEvent;
+ friend class AttachDispayEvent;
+ friend class CursorUpdateEvent;
private:
CursorCache _cursor_cache;
CursorData* _cursor;
- CursorModeTrigger _cursor_trigger;
Point _hot_pos;
Rect _cursor_rect;
Mutex _update_lock;
bool _cursor_visible;
+ DisplayChannel* _display_channel;
};
#endif
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index ed8f2c9b..9f8fba80 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -41,6 +41,8 @@
#endif
#include "platform_utils.h"
#include "ffmpeg_inc.h"
+#include "inputs_channel.h"
+#include "cursor_channel.h"
static Mutex avcodec_mutex;
@@ -599,7 +601,7 @@ StreamsTimer::StreamsTimer(DisplayChannel& channel)
{
}
-void StreamsTimer::response(AbstractProcessLoop &events_loop)
+void StreamsTimer::response(AbstractProcessLoop& events_loop)
{
_channel.streams_time();
}
@@ -609,13 +611,13 @@ void StreamsTimer::response(AbstractProcessLoop &events_loop)
class ResetTimer: public Timer {
public:
ResetTimer(RedScreen* screen, RedClient& client) : _screen(screen), _client(client) {}
- virtual void response(AbstractProcessLoop &events_loop);
+ virtual void response(AbstractProcessLoop& events_loop);
private:
RedScreen* _screen;
RedClient& _client;
};
-void ResetTimer::response(AbstractProcessLoop &events_loop)
+void ResetTimer::response(AbstractProcessLoop& events_loop)
{
_screen->unref();
_client.deactivate_interval_timer(this);
@@ -639,6 +641,10 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id,
, _update_mark (0)
, _streams_timer (new StreamsTimer(*this))
, _next_timer_time (0)
+ , _cursor_visibal (false)
+ , _active_pointer (false)
+ , _capture_mouse_mode (false)
+ , _inputs_channel (NULL)
, _active_streams (NULL)
, _streams_trigger (*this)
#ifdef USE_OGL
@@ -801,6 +807,130 @@ void DisplayChannel::recreate_ogl_context()
#endif
+void DisplayChannel::update_cursor()
+{
+ if (!screen() || !_active_pointer) {
+ return;
+ }
+
+ if (_capture_mouse_mode) {
+ //todo: use special cursor for capture mode
+ AutoRef<LocalCursor> default_cursor(Platform::create_default_cursor());
+ screen()->set_cursor(*default_cursor);
+ return;
+ }
+
+ if (!_cursor_visibal || !*_cursor) {
+ screen()->hide_cursor();
+ return;
+ }
+
+
+ if (!(*_cursor)->get_local()) {
+ AutoRef<LocalCursor> local_cursor(Platform::create_local_cursor(*_cursor));
+ if (*local_cursor == NULL) {
+ THROW("create local cursor failed");
+ }
+ (*_cursor)->set_local(*local_cursor);
+ }
+ screen()->set_cursor((*_cursor)->get_local());
+}
+
+void DisplayChannel::set_cursor(CursorData* cursor)
+{
+ ASSERT(cursor);
+ _cursor.reset(cursor->ref());
+ _cursor_visibal = true;
+ update_cursor();
+}
+
+void DisplayChannel::hide_cursor()
+{
+ _cursor_visibal = false;
+ update_cursor();
+}
+
+void DisplayChannel::attach_inputs(InputsChannel* inputs_channel)
+{
+ if (_inputs_channel) {
+ return;
+ }
+
+ _inputs_channel = inputs_channel;
+ if (_active_pointer && !_capture_mouse_mode) {
+ _inputs_channel->on_mouse_position(_pointer_pos.x, _pointer_pos.y,
+ _buttons_state, get_id());
+ }
+}
+
+void DisplayChannel::detach_inputs()
+{
+ _inputs_channel = NULL;
+}
+
+bool DisplayChannel::pointer_test(int x, int y)
+{
+ return contains_point(x, y);
+}
+
+void DisplayChannel::on_pointer_enter(int x, int y, unsigned int buttons_state)
+{
+ _active_pointer = true;
+ update_cursor();
+ on_pointer_motion(x, y, buttons_state);
+}
+
+void DisplayChannel::on_pointer_motion(int x, int y, unsigned int buttons_state)
+{
+ _pointer_pos.x = x;
+ _pointer_pos.y = y;
+ _buttons_state = buttons_state;
+ if (!_capture_mouse_mode && _inputs_channel) {
+ _inputs_channel->on_mouse_position(x, y, buttons_state, get_id());
+ }
+}
+
+void DisplayChannel::on_pointer_leave()
+{
+ _active_pointer = false;
+}
+
+void DisplayChannel::on_mouse_button_press(int button, int buttons_state)
+{
+ _buttons_state = buttons_state;
+ if (!_capture_mouse_mode && _inputs_channel) {
+ _inputs_channel->on_mouse_down(button, buttons_state);
+ }
+}
+
+void DisplayChannel::on_mouse_button_release(int button, int buttons_state)
+{
+ _buttons_state = buttons_state;
+ if (_capture_mouse_mode) {
+ if (button == REDC_MOUSE_LBUTTON) {
+ get_client().on_mouse_capture_trigger(*screen());
+ }
+ return;
+ }
+
+ if (_inputs_channel) {
+ _inputs_channel->on_mouse_up(button, buttons_state);
+ }
+}
+
+void DisplayChannel::set_capture_mode(bool on)
+{
+ if (_capture_mouse_mode == on) {
+ return;
+ }
+ _capture_mouse_mode = on;
+ update_cursor();
+ if (_inputs_channel && !_capture_mouse_mode && _active_pointer) {
+ _inputs_channel->on_mouse_position(_pointer_pos.x, _pointer_pos.y, _buttons_state,
+ get_id());
+ }
+}
+
void DisplayChannel::update_interrupt()
{
if (!_canvas.get() || !screen()) {
@@ -865,6 +995,77 @@ private:
DisplayChannel& _channel;
};
+class AttachChannelsEvent : public Event {
+public:
+ AttachChannelsEvent(DisplayChannel& channel) : Event(), _channel (channel) {}
+
+ class AttachChannels: public ForEachChannelFunc {
+ public:
+ AttachChannels(DisplayChannel& channel)
+ : _channel (channel)
+ {
+ }
+
+ virtual bool operator() (RedChannel& channel)
+ {
+ if (channel.get_type() == RED_CHANNEL_CURSOR && channel.get_id() == _channel.get_id()) {
+ static_cast<CursorChannel&>(channel).attach_display(&_channel);
+ } else if (channel.get_type() == RED_CHANNEL_INPUTS) {
+ _channel.attach_inputs(&static_cast<InputsChannel&>(channel));
+ }
+ return false;
+ }
+
+ private:
+ DisplayChannel& _channel;
+ };
+
+ virtual void response(AbstractProcessLoop& events_loop)
+ {
+ uint32_t mouse_mode = _channel.get_client().get_mouse_mode();
+ _channel._capture_mouse_mode = (mouse_mode == RED_MOUSE_MODE_SERVER);
+ AttachChannels for_each_func(_channel);
+ _channel.get_client().for_each_channel(for_each_func);
+ }
+
+private:
+ DisplayChannel& _channel;
+};
+
+class DetachChannelsEvent : public Event {
+public:
+ DetachChannelsEvent(DisplayChannel& channel) : Event(), _channel (channel) {}
+
+ class DetatchChannels: public ForEachChannelFunc {
+ public:
+ DetatchChannels(DisplayChannel& channel)
+ : _channel (channel)
+ {
+ }
+
+ virtual bool operator() (RedChannel& channel)
+ {
+ if (channel.get_type() == RED_CHANNEL_CURSOR && channel.get_id() == _channel.get_id()) {
+ static_cast<CursorChannel&>(channel).detach_display();
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ DisplayChannel& _channel;
+ };
+
+ virtual void response(AbstractProcessLoop& events_loop)
+ {
+ DetatchChannels for_each_func(_channel);
+ _channel.get_client().for_each_channel(for_each_func);
+ }
+
+private:
+ DisplayChannel& _channel;
+};
+
void DisplayChannel::on_connect()
{
Message* message = new Message(REDC_DISPLAY_INIT, sizeof(RedcDisplayInit));
@@ -874,6 +1075,8 @@ void DisplayChannel::on_connect()
init->glz_dictionary_id = 1;
init->glz_dictionary_window_size = get_client().get_glz_window_size();
post_message(message);
+ AutoRef<AttachChannelsEvent> attach_channels(new AttachChannelsEvent(*this));
+ get_client().push_event(*attach_channels);
}
void DisplayChannel::on_disconnect()
@@ -885,6 +1088,8 @@ void DisplayChannel::on_disconnect()
if (screen()) {
screen()->set_update_interrupt_trigger(NULL);
}
+ AutoRef<DetachChannelsEvent> detach_channels(new DetachChannelsEvent(*this));
+ get_client().push_event(*detach_channels);
detach_from_screen(get_client().get_application());
get_client().deactivate_interval_timer(*_streams_timer);
AutoRef<SyncEvent> sync_event(new SyncEvent());
@@ -1030,7 +1235,6 @@ void DisplayChannel::handle_mode(RedPeer::InMessage* message)
if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) {
screen()->unset_type_gl();
screen()->untouch_context();
- //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
}
}
diff --git a/client/display_channel.h b/client/display_channel.h
index 8600bfb4..e58be919 100644
--- a/client/display_channel.h
+++ b/client/display_channel.h
@@ -35,6 +35,8 @@ class RedScreen;
class ChannelFactory;
class VideoStream;
class DisplayChannel;
+class CursorData;
+class InputsChannel;
class StreamsTrigger: public EventSources::Trigger {
public:
@@ -93,6 +95,19 @@ public:
virtual void post_migrate();
#endif
virtual void update_interrupt();
+ void set_cursor(CursorData* cursor);
+ void hide_cursor();
+ void set_capture_mode(bool on);
+
+ virtual bool pointer_test(int x, int y);
+ virtual void on_pointer_enter(int x, int y, unsigned int buttons_state);
+ virtual void on_pointer_motion(int x, int y, unsigned int buttons_state);
+ virtual void on_pointer_leave();
+ virtual void on_mouse_button_press(int button, int buttons_state);
+ virtual void on_mouse_button_release(int button, int buttons_state);
+
+ void attach_inputs(InputsChannel* inputs_channel);
+ void detach_inputs();
static ChannelFactory& Factory();
@@ -115,6 +130,7 @@ private:
void create_canvas(const std::vector<int>& canvas_type, int width, int height,
int depth);
void destroy_strams();
+ void update_cursor();
void handle_mode(RedPeer::InMessage* message);
void handle_mark(RedPeer::InMessage* message);
@@ -175,6 +191,15 @@ private:
AutoRef<StreamsTimer> _streams_timer;
uint32_t _next_timer_time;
+ AutoRef<CursorData> _cursor;
+ bool _cursor_visibal;
+ bool _active_pointer;
+ bool _capture_mouse_mode;
+ InputsChannel* _inputs_channel;
+
+ Point _pointer_pos;
+ int _buttons_state;
+
std::vector<VideoStream*> _streams;
VideoStream* _active_streams;
StreamsTrigger _streams_trigger;
@@ -182,12 +207,15 @@ private:
GLInterruptRecreate _gl_interrupt_recreate;
#endif
InterruptUpdate _interrupt_update;
+
friend class SetModeEvent;
friend class ActivateTimerEvent;
friend class VideoStream;
friend class StreamsTrigger;
friend class GLInterupt;
friend class StreamsTimer;
+ friend class AttachChannelsEvent;
+ friend class DetachChannelsEvent;
};
#endif
diff --git a/client/inputs_channel.cpp b/client/inputs_channel.cpp
index df434937..e1b63964 100644
--- a/client/inputs_channel.cpp
+++ b/client/inputs_channel.cpp
@@ -21,6 +21,7 @@
#include "debug.h"
#include "red_client.h"
#include "application.h"
+#include "display_channel.h"
#define SYNC_REMOTH_MODIFIRES
@@ -28,9 +29,30 @@ class SetInputsHandlerEvent: public Event {
public:
SetInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {}
+ class AttachFunc: public ForEachChannelFunc {
+ public:
+ AttachFunc(InputsChannel& channel)
+ : _channel (channel)
+ {
+ }
+
+ virtual bool operator() (RedChannel& channel)
+ {
+ if (channel.get_type() == RED_CHANNEL_DISPLAY) {
+ static_cast<DisplayChannel&>(channel).attach_inputs(&_channel);
+ }
+ return true;
+ }
+
+ public:
+ InputsChannel& _channel;
+ };
+
virtual void response(AbstractProcessLoop& events_loop)
{
static_cast<Application*>(events_loop.get_owner())->set_inputs_handler(_channel);
+ AttachFunc func(_channel);
+ _channel.get_client().for_each_channel(func);
}
private:
@@ -56,9 +78,22 @@ class RemoveInputsHandlerEvent: public SyncEvent {
public:
RemoveInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {}
+ class DetachFunc: public ForEachChannelFunc {
+ public:
+ virtual bool operator() (RedChannel& channel)
+ {
+ if (channel.get_type() == RED_CHANNEL_DISPLAY) {
+ static_cast<DisplayChannel&>(channel).detach_inputs();
+ }
+ return true;
+ }
+ };
+
virtual void do_response(AbstractProcessLoop& events_loop)
{
static_cast<Application*>(events_loop.get_owner())->remove_inputs_handler(_channel);
+ DetachFunc detach_func;
+ _channel.get_client().for_each_channel(detach_func);
}
private:
diff --git a/client/inputs_channel.h b/client/inputs_channel.h
index 25341e18..530cd8ba 100644
--- a/client/inputs_channel.h
+++ b/client/inputs_channel.h
@@ -29,13 +29,14 @@ public:
virtual ~InputsChannel();
virtual void on_mouse_motion(int dx, int dy, int buttons_state);
- virtual void on_mouse_position(int x, int y, int buttons_state, int display_id);
virtual void on_mouse_down(int button, int buttons_state);
virtual void on_mouse_up(int button, int buttons_state);
virtual void on_key_down(uint32_t scan_code);
virtual void on_key_up(uint32_t scan_code);
virtual void on_focus_in();
+ void on_mouse_position(int x, int y, int buttons_state, int display_id);
+
static ChannelFactory& Factory();
protected:
@@ -69,6 +70,8 @@ private:
friend class MotionMessage;
friend class PositionMessage;
friend class KeyModifiersEvent;
+ friend class SetInputsHandlerEvent;
+ friend class RemoveInputsHandlerEvent;
};
diff --git a/client/inputs_handler.h b/client/inputs_handler.h
index 3fd557e4..bfde48dc 100644
--- a/client/inputs_handler.h
+++ b/client/inputs_handler.h
@@ -23,7 +23,6 @@ class InputsHandler {
public:
virtual ~InputsHandler() {}
virtual void on_mouse_motion(int dx, int dy, int buttons_state) {}
- virtual void on_mouse_position(int x, int y, int buttons_state, int display_id) {}
virtual void on_mouse_down(int button, int buttons_state) {}
virtual void on_mouse_up(int button, int buttons_state) {}
virtual void on_key_down(uint32_t scan_code) {}
diff --git a/client/red_client.cpp b/client/red_client.cpp
index cf4562b3..25fd5c78 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -23,6 +23,48 @@
#include "utils.h"
#include "debug.h"
+
+class MouseModeEvent: public Event {
+public:
+ MouseModeEvent(RedClient& client)
+ : _client (client)
+ {
+ }
+
+ class SetModeFunc: public ForEachChannelFunc {
+ public:
+ SetModeFunc(bool capture_mode)
+ : _capture_mode (capture_mode)
+ {
+ }
+
+ virtual bool operator() (RedChannel& channel)
+ {
+ if (channel.get_type() == RED_CHANNEL_DISPLAY) {
+ static_cast<DisplayChannel&>(channel).set_capture_mode(_capture_mode);
+ }
+ return true;
+ }
+
+ public:
+ bool _capture_mode;
+ };
+
+ virtual void response(AbstractProcessLoop& events_loop)
+ {
+ bool capture_mode = _client.get_mouse_mode() == RED_MOUSE_MODE_SERVER;
+ if (!capture_mode) {
+ _client.get_application().release_mouse_capture();
+ }
+
+ SetModeFunc func(capture_mode);
+ _client.for_each_channel(func);
+ }
+
+private:
+ RedClient& _client;
+};
+
Migrate::Migrate(RedClient& client)
: _client (client)
, _running (false)
@@ -344,6 +386,9 @@ void RedClient::on_disconnect()
_agent_msg_data = NULL;
_agent_msg_pos = 0;
_agent_tokens = 0;
+ AutoRef<SyncEvent> sync_event(new SyncEvent());
+ get_client().push_event(*sync_event);
+ (*sync_event)->wait();
}
void RedClient::delete_channels()
@@ -357,6 +402,19 @@ void RedClient::delete_channels()
}
}
+void RedClient::for_each_channel(ForEachChannelFunc& func)
+{
+ Lock lock(_channels_lock);
+ Channels::iterator iter = _channels.begin();
+ for (; iter != _channels.end() && func(**iter) ;iter++);
+}
+
+
+void RedClient::on_mouse_capture_trigger(RedScreen& screen)
+{
+ _application.capture_mouse();
+}
+
RedPeer::ConnectionOptions::Type RedClient::get_connection_options(uint32_t channel_type)
{
return _con_opt_map[channel_type];
@@ -611,9 +669,11 @@ void RedClient::set_mouse_mode(uint32_t supported_modes, uint32_t current_mode)
Channels::iterator iter = _channels.begin();
for (; iter != _channels.end(); ++iter) {
if ((*iter)->get_type() == RED_CHANNEL_CURSOR) {
- ((CursorChannel *)(*iter))->set_cursor_mode();
+ ((CursorChannel *)(*iter))->on_mouse_mode_change();
}
}
+ AutoRef<MouseModeEvent> event(new MouseModeEvent(*this));
+ push_event(*event);
}
// FIXME: use configured mouse mode (currently, use client mouse mode if supported by server)
if ((supported_modes & RED_MOUSE_MODE_CLIENT) && (current_mode != RED_MOUSE_MODE_CLIENT)) {
diff --git a/client/red_client.h b/client/red_client.h
index 04c800cc..fde958f2 100644
--- a/client/red_client.h
+++ b/client/red_client.h
@@ -118,6 +118,11 @@ class AgentTimer: public Timer {
typedef std::map< int, RedPeer::ConnectionOptions::Type> PeerConnectionOptMap;
+class ForEachChannelFunc {
+public:
+ virtual bool operator() (RedChannel& channel) = 0;
+};
+
class RedClient: public RedChannel {
public:
friend class RedChannel;
@@ -153,6 +158,8 @@ public:
PixmapCache& get_pixmap_cache() {return _pixmap_cache;}
uint64_t get_pixmap_cache_size() { return _pixmap_cache_size;}
void on_display_mode_change();
+ void for_each_channel(ForEachChannelFunc& func);
+ void on_mouse_capture_trigger(RedScreen& screen);
GlzDecoderWindow& get_glz_window() {return _glz_window;}
int get_glz_window_size() { return _glz_window_size;}
diff --git a/client/red_window.h b/client/red_window.h
index 0d3e781a..4b1d2443 100644
--- a/client/red_window.h
+++ b/client/red_window.h
@@ -92,7 +92,7 @@ public:
private:
void on_focus_in();
void on_focus_out();
- void on_pointer_enter();
+ void on_pointer_enter(int x, int y, unsigned int buttons_state);
void on_pointer_leave();
void do_start_key_interception();
@@ -117,15 +117,19 @@ class RedWindow::Listener {
public:
virtual ~Listener() {}
virtual void on_exposed_rect(const Rect& area) = 0;
- virtual void on_mouse_motion(int x, int y, unsigned int buttons_state) = 0;
+
+ virtual void on_pointer_enter(int x, int y, unsigned int buttons_state) = 0;
+ virtual void on_pointer_motion(int x, int y, unsigned int buttons_state) = 0;
+ virtual void on_pointer_leave() = 0;
+ virtual void on_mouse_button_press(RedButton button, unsigned int buttons_state) = 0;
+ virtual void on_mouse_button_release(RedButton button, unsigned int buttons_state) = 0;
+
virtual void on_key_press(RedKey key) = 0;
virtual void on_key_release(RedKey key) = 0;
- virtual void on_button_press(RedButton button, unsigned int buttons_state) = 0;
- virtual void on_button_release(RedButton button, unsigned int buttons_state) = 0;
+
virtual void on_deactivate() = 0;
virtual void on_activate() = 0;
- virtual void on_pointer_enter() = 0;
- virtual void on_pointer_leave() = 0;
+
virtual void on_start_key_interception() = 0;
virtual void on_stop_key_interception() = 0;
virtual void enter_modal_loop() = 0;
diff --git a/client/screen.cpp b/client/screen.cpp
index bbc76e75..50905710 100644
--- a/client/screen.cpp
+++ b/client/screen.cpp
@@ -43,6 +43,29 @@ private:
int _screen;
};
+class LayerChangedEvent: public Event {
+public:
+ LayerChangedEvent (int screen) : _screen (screen) {}
+
+ virtual void response(AbstractProcessLoop& events_loop)
+ {
+ Application* app = static_cast<Application*>(events_loop.get_owner());
+ RedScreen* screen = app->find_screen(_screen);
+ if (screen) {
+ Lock lock(screen->_layer_changed_lock);
+ screen->_active_layer_change_event = false;
+ lock.unlock();
+ if (screen->_pointer_on_screen) {
+ screen->update_pointer_layer();
+ }
+ }
+ }
+
+private:
+ int _screen;
+};
+
+
void UpdateTimer::response(AbstractProcessLoop& events_loop)
{
_screen->periodic_update();
@@ -54,11 +77,9 @@ RedScreen::RedScreen(Application& owner, int id, const std::wstring& name, int w
, _refs (1)
, _window (*this)
, _active (false)
- , _captured (false)
, _full_screen (false)
, _out_of_sync (false)
, _frame_area (false)
- , _cursor_visible (true)
, _periodic_update (false)
, _key_interception (false)
, _update_by_timer (true)
@@ -68,11 +89,13 @@ RedScreen::RedScreen(Application& owner, int id, const std::wstring& name, int w
, _update_mark (1)
, _monitor (NULL)
, _default_cursor (NULL)
- , _active_cursor (NULL)
, _inactive_cursor (NULL)
- , _pointer_location (POINTER_OUTSIDE_WINDOW)
, _pixel_format_index (0)
, _update_interrupt_trigger (NULL)
+ , _pointer_layer (NULL)
+ , _mouse_captured (false)
+ , _active_layer_change_event (false)
+ , _pointer_on_screen (false)
{
region_init(&_dirty_region);
set_name(name);
@@ -98,9 +121,9 @@ RedScreen::RedScreen(Application& owner, int id, const std::wstring& name, int w
RedScreen::~RedScreen()
{
- bool captured = is_captured();
+ bool captured = is_mouse_captured();
_window.stop_key_interception();
- relase_inputs();
+ relase_mouse();
destroy_composit_area();
_owner.deactivate_interval_timer(*_update_timer);
_owner.on_screen_destroyed(_id, captured);
@@ -108,9 +131,7 @@ RedScreen::~RedScreen()
if (_default_cursor) {
_default_cursor->unref();
}
- if (_active_cursor) {
- _active_cursor->unref();
- }
+
if (_inactive_cursor) {
_inactive_cursor->unref();
}
@@ -168,7 +189,7 @@ void RedScreen::set_mode(int width, int height, int depth)
bool cuptur = _owner.rearrange_monitors(*this);
__show_full_screen();
if (cuptur) {
- capture_inputs();
+ capture_mouse();
}
} else {
_window.resize(_size.x, _size.y);
@@ -184,6 +205,17 @@ void RedScreen::set_name(const std::wstring& name)
_window.set_title(_name);
}
+void RedScreen::on_layer_changed(ScreenLayer& layer)
+{
+ Lock lock(_layer_changed_lock);
+ if (_active_layer_change_event) {
+ return;
+ }
+ _active_layer_change_event = true;
+ AutoRef<LayerChangedEvent> change_event(new LayerChangedEvent(_id));
+ _owner.push_event(*change_event);
+}
+
void RedScreen::attach_layer(ScreenLayer& layer)
{
RecurciveLock lock(_update_lock);
@@ -200,11 +232,22 @@ void RedScreen::attach_layer(ScreenLayer& layer)
ref();
lock.unlock();
layer.invalidate();
+ if (_pointer_on_screen) {
+ update_pointer_layer();
+ }
}
void RedScreen::detach_layer(ScreenLayer& layer)
{
+ bool need_pointer_layer_update = false;
+ if (_pointer_layer == &layer) {
+ _pointer_layer->on_pointer_leave();
+ _pointer_layer = NULL;
+ need_pointer_layer_update = true;
+ }
+
RecurciveLock lock(_update_lock);
+
int order = layer.z_order();
if ((int)_layes.size() < order + 1 || _layes[order] != &layer) {
@@ -218,6 +261,9 @@ void RedScreen::detach_layer(ScreenLayer& layer)
invalidate(layer_area);
region_destroy(&layer_area);
unref();
+ if (need_pointer_layer_update && !update_pointer_layer()) {
+ _window.set_cursor(_inactive_cursor);
+ }
}
void RedScreen::composit_to_screen(RedDrawable& win_dc, const QRegion& region)
@@ -427,121 +473,180 @@ void RedScreen::reset_mouse_pos()
_window.set_mouse_position(_mouse_anchor_point.x, _mouse_anchor_point.y);
}
-void RedScreen::capture_inputs()
+void RedScreen::capture_mouse()
{
- if (_captured || !_window.get_mouse_anchor_point(_mouse_anchor_point)) {
+ if (_mouse_captured || !_window.get_mouse_anchor_point(_mouse_anchor_point)) {
return;
}
- if (_owner.get_mouse_mode() == RED_MOUSE_MODE_SERVER) {
- _window.hide_cursor();
- reset_mouse_pos();
- _window.cupture_mouse();
+
+ if (_pointer_layer) {
+ _pointer_layer->on_pointer_leave();
+ _pointer_layer = NULL;
}
- _captured = true;
+ _pointer_on_screen = false;
+ _mouse_captured = true;
+ _window.hide_cursor();
+ reset_mouse_pos();
+ _window.cupture_mouse();
}
-void RedScreen::relase_inputs()
+void RedScreen::relase_mouse()
{
- if (!_captured) {
+ if (!_mouse_captured) {
return;
}
- _captured = false;
+ _mouse_captured = false;
_window.release_mouse();
- if (_owner.get_mouse_mode() == RED_MOUSE_MODE_SERVER) {
- _window.set_cursor(_default_cursor);
+ update_pointer_layer();
+}
+
+void RedScreen::set_cursor(LocalCursor* cursor)
+{
+ if (_mouse_captured) {
+ return;
}
+
+ _window.set_cursor(cursor);
+}
+
+void RedScreen::hide_cursor()
+{
+ _window.hide_cursor();
}
-void RedScreen::set_cursor(CursorData* cursor)
+ScreenLayer* RedScreen::find_pointer_layer()
{
- if (cursor) {
- if (_active_cursor) {
- _active_cursor->unref();
+ for (int i = _layes.size() - 1; i >= 0; i--) {
+ ScreenLayer* layer;
+
+ if (!(layer = _layes[i])) {
+ continue;
}
- if (!cursor->get_local()) {
- AutoRef<LocalCursor> cur(Platform::create_local_cursor(cursor));
- if (*cur == NULL) {
- THROW("create local cursor failed");
- }
- cursor->set_local(*cur);
- _active_cursor = (*cur)->ref();
- } else {
- _active_cursor = (cursor->get_local())->ref();
+
+ if (layer->pointer_test(_pointer_pos.x, _pointer_pos.y)) {
+ return layer;
}
}
- _cursor_visible = !!cursor;
- update_active_cursor();
+ return NULL;
}
-void RedScreen::update_active_cursor()
+bool RedScreen::update_pointer_layer()
{
- if (_owner.get_mouse_mode() == RED_MOUSE_MODE_CLIENT &&
- _pointer_location == POINTER_IN_ACTIVE_AREA) {
- if (_cursor_visible && _active_cursor) {
- _window.set_cursor(_active_cursor);
- } else {
- _window.hide_cursor();
- }
+ ASSERT(!_mouse_captured);
+
+ ScreenLayer* now = find_pointer_layer();
+
+ if (now == _pointer_layer) {
+ return false;
+ }
+
+ if (_pointer_layer) {
+ _pointer_layer->on_pointer_leave();
+ }
+
+ _pointer_layer = find_pointer_layer();
+
+ if (_pointer_layer) {
+ _pointer_layer->on_pointer_enter(_pointer_pos.x, _pointer_pos.y, _mouse_botton_state);
+ } else {
+ set_cursor(_inactive_cursor);
+ }
+
+ return true;
+}
+
+void RedScreen::on_pointer_enter(int x, int y, unsigned int buttons_state)
+{
+ if (_mouse_captured) {
+ return;
+ }
+
+ _pointer_on_screen = true;
+ _pointer_pos.x = x;
+ _pointer_pos.y = y;
+ _mouse_botton_state = buttons_state;
+
+ ScreenLayer* layer = find_pointer_layer();
+ if (!layer) {
+ set_cursor(_inactive_cursor);
+ return;
+ }
+
+ _pointer_layer = layer;
+ _pointer_layer->on_pointer_enter(_pointer_pos.x, _pointer_pos.y, buttons_state);
+
+ if (_full_screen) {
+ /* allowing enterance to key interception mode without
+ requiring the user to press the window
+ */
+ activate();
}
}
void RedScreen::on_mouse_motion(int x, int y, unsigned int buttons_state)
{
- switch (_owner.get_mouse_mode()) {
- case RED_MOUSE_MODE_CLIENT:
- if (!_frame_area) {
- _owner.on_mouse_position(x, y, buttons_state, _id);
- } else if (x >= 0 && x < _size.x && y >= 0 && y < _size.y) {
- _owner.on_mouse_position(x, y, buttons_state, _id);
- if (_pointer_location != POINTER_IN_ACTIVE_AREA) {
- _pointer_location = POINTER_IN_ACTIVE_AREA;
- update_active_cursor();
- }
- } else if (_pointer_location != POINTER_IN_FRAME_AREA) {
- _pointer_location = POINTER_IN_FRAME_AREA;
- _window.set_cursor(_inactive_cursor);
- }
- break;
- case RED_MOUSE_MODE_SERVER:
- if (_captured && (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();
- }
- break;
- default:
- THROW("invalid mouse mode");
+ 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 RedScreen::on_button_press(RedButton button, unsigned int buttons_state)
+void RedScreen::on_pointer_motion(int x, int y, unsigned int buttons_state)
{
- if (_owner.get_mouse_mode() == RED_MOUSE_MODE_CLIENT &&
- _pointer_location != POINTER_IN_ACTIVE_AREA) {
+ if (_mouse_captured) {
+ on_mouse_motion(x, y, buttons_state);
return;
}
- if (!mouse_is_captured()) {
- if (_owner.get_mouse_mode() == RED_MOUSE_MODE_SERVER && button != REDC_MOUSE_LBUTTON) {
- return;
- }
- capture_inputs();
- if (_owner.get_mouse_mode() == RED_MOUSE_MODE_SERVER) {
- return;
- }
+
+ _pointer_pos.x = x;
+ _pointer_pos.y = y;
+ _mouse_botton_state = buttons_state;
+
+ if (update_pointer_layer() || !_pointer_layer) {
+ return;
}
- _owner.on_mouse_down(button, buttons_state);
+
+ _pointer_layer->on_pointer_motion(x, y, buttons_state);
}
-void RedScreen::on_button_release(RedButton button, unsigned int buttons_state)
+void RedScreen::on_mouse_button_press(RedButton button, unsigned int buttons_state)
{
- if (!mouse_is_captured()) {
- if (_owner.get_mouse_mode() == RED_MOUSE_MODE_SERVER) {
- return;
- }
- capture_inputs();
+ if (_mouse_captured) {
+ _owner.on_mouse_down(button, buttons_state);
+ return;
+ }
+
+ if (!_pointer_layer) {
+ return;
+ }
+
+ _pointer_layer->on_mouse_button_press(button, buttons_state);
+}
+
+void RedScreen::on_mouse_button_release(RedButton button, unsigned int buttons_state)
+{
+ if (_mouse_captured) {
+ _owner.on_mouse_up(button, buttons_state);
+ return;
}
- _owner.on_mouse_up(button, buttons_state);
+
+ if (!_pointer_layer) {
+ return;
+ }
+ _pointer_layer->on_mouse_button_release(button, buttons_state);
+}
+
+void RedScreen::on_pointer_leave()
+{
+ ASSERT(!_mouse_captured);
+
+ if (_pointer_layer) {
+ _pointer_layer->on_pointer_leave();
+ _pointer_layer = NULL;
+ }
+ _pointer_on_screen = false;
}
void RedScreen::on_key_press(RedKey key)
@@ -556,7 +661,7 @@ void RedScreen::on_key_release(RedKey key)
void RedScreen::on_deactivate()
{
- relase_inputs();
+ relase_mouse();
_active = false;
_owner.on_deactivate_screen(this);
}
@@ -567,23 +672,6 @@ void RedScreen::on_activate()
_owner.on_activate_screen(this);
}
-void RedScreen::on_pointer_enter()
-{
- if (!_frame_area) {
- _pointer_location = POINTER_IN_ACTIVE_AREA;
- update_active_cursor();
- if (_full_screen) {
- /* allowing enterance to key interception mode without
- requiring the user to press the window */
- activate();
- }
- }
-}
-
-void RedScreen::on_pointer_leave()
-{
- _pointer_location = POINTER_OUTSIDE_WINDOW;
-}
void RedScreen::on_start_key_interception()
{
diff --git a/client/screen.h b/client/screen.h
index b191d099..10c8fd4f 100644
--- a/client/screen.h
+++ b/client/screen.h
@@ -57,20 +57,22 @@ public:
void attach_layer(ScreenLayer& layer);
void detach_layer(ScreenLayer& layer);
+ void on_layer_changed(ScreenLayer& layer);
void set_mode(int width, int height, int depth);
void set_name(const std::wstring& name);
uint64_t invalidate(const Rect& rect, bool urgent);
void invalidate(const QRegion &region);
- void relase_inputs();
- void capture_inputs();
- bool is_captured() { return _captured;}
+ void capture_mouse();
+ void relase_mouse();
+ bool is_mouse_captured() { return _mouse_captured;}
bool intercepts_sys_key() { return _key_interception;}
Point get_size() { return _size;}
bool has_monitor() { return _monitor != 0;}
void set_monitor(Monitor *monitor) { _monitor = monitor;}
Monitor* get_monitor() { return _monitor;}
RedWindow* get_window() { return &_window;}
- void set_cursor(CursorData* cursor);
+ void set_cursor(LocalCursor* cursor);
+ void hide_cursor();
void exit_full_screen();
void minimize();
void show(bool activate, RedScreen* pos);
@@ -123,19 +125,23 @@ private:
void composit_to_screen(RedDrawable& win_dc, const QRegion& region);
void reset_mouse_pos();
- bool mouse_is_captured() { return _captured;}
- void update_active_cursor();
+ ScreenLayer* find_pointer_layer();
+ bool update_pointer_layer();
virtual void on_exposed_rect(const Rect& area);
- virtual void on_mouse_motion(int x, int y, unsigned int buttons_state);
+ virtual void on_pointer_enter(int x, int y, unsigned int buttons_state);
+ virtual void on_pointer_motion(int x, int y, unsigned int buttons_state);
+ virtual void on_pointer_leave();
+ void on_mouse_motion(int x, int y, unsigned int buttons_state);
+ virtual void on_mouse_button_press(RedButton button, unsigned int buttons_state);
+ virtual void on_mouse_button_release(RedButton button, unsigned int buttons_state);
+
virtual void on_key_press(RedKey key);
virtual void on_key_release(RedKey key);
- virtual void on_button_press(RedButton button, unsigned int buttons_state);
- virtual void on_button_release(RedButton button, unsigned int buttons_state);
+
virtual void on_deactivate();
virtual void on_activate();
- virtual void on_pointer_enter();
- virtual void on_pointer_leave();
+
virtual void on_start_key_interception();
virtual void on_stop_key_interception();
virtual void enter_modal_loop();
@@ -154,11 +160,9 @@ private:
QRegion _dirty_region;
RecurciveMutex _update_lock;
bool _active;
- bool _captured;
bool _full_screen;
bool _out_of_sync;
bool _frame_area;
- bool _cursor_visible;
bool _periodic_update;
bool _key_interception;
bool _update_by_timer;
@@ -174,17 +178,20 @@ private:
Monitor* _monitor;
LocalCursor* _default_cursor;
- LocalCursor* _active_cursor;
LocalCursor* _inactive_cursor;
- enum PointerLocation {
- POINTER_IN_ACTIVE_AREA,
- POINTER_IN_FRAME_AREA,
- POINTER_OUTSIDE_WINDOW,
- };
- PointerLocation _pointer_location;
int _pixel_format_index;
EventSources::Trigger *_update_interrupt_trigger;
+
+ ScreenLayer* _pointer_layer;
+ bool _mouse_captured;
+ Mutex _layer_changed_lock;
+ bool _active_layer_change_event;
+ bool _pointer_on_screen;
+ Point _pointer_pos;
+ unsigned int _mouse_botton_state;
+
+ friend class LayerChangedEvent;
};
#endif
diff --git a/client/screen_layer.cpp b/client/screen_layer.cpp
index 9940ad86..d4a4435f 100644
--- a/client/screen_layer.cpp
+++ b/client/screen_layer.cpp
@@ -108,6 +108,13 @@ void ScreenLayer::invalidate()
invalidate(_area);
}
+void ScreenLayer::notify_changed()
+{
+ if (_screen) {
+ _screen->on_layer_changed(*this);
+ }
+}
+
void ScreenLayer::set_area(const QRegion& area)
{
Lock lock(_area_lock);
@@ -115,6 +122,7 @@ void ScreenLayer::set_area(const QRegion& area)
region_destroy(&_area);
region_clone(&_area, &area);
invalidate();
+ notify_changed();
}
void ScreenLayer::clear_area()
@@ -122,6 +130,7 @@ void ScreenLayer::clear_area()
Lock lock(_area_lock);
invalidate();
region_clear(&_area);
+ notify_changed();
}
void ScreenLayer::set_rect_area(const Rect& r)
@@ -131,6 +140,7 @@ void ScreenLayer::set_rect_area(const Rect& r)
region_clear(&_area);
region_add(&_area, &r);
invalidate();
+ notify_changed();
}
void ScreenLayer::offset_area(int dx, int dy)
@@ -139,12 +149,14 @@ void ScreenLayer::offset_area(int dx, int dy)
invalidate();
region_offset(&_area, dx, dy);
invalidate();
+ notify_changed();
}
void ScreenLayer::add_rect_area(const Rect& r)
{
Lock lock(_area_lock);
region_add(&_area, &r);
+ notify_changed();
}
void ScreenLayer::remove_rect_area(const Rect& r)
@@ -152,6 +164,7 @@ void ScreenLayer::remove_rect_area(const Rect& r)
Lock lock(_area_lock);
invalidate();
region_remove(&_area, &r);
+ notify_changed();
}
void ScreenLayer::begin_update(QRegion& direct_rgn, QRegion& composit_rgn)
@@ -175,6 +188,12 @@ void ScreenLayer::begin_update(QRegion& direct_rgn, QRegion& composit_rgn)
}
}
+bool ScreenLayer::contains_point(int x, int y)
+{
+ Lock lock(_area_lock);
+ return !!region_contains_point(&_area, x, y);
+}
+
void ScreenLayer::attach_to_screen(Application& applicaion, int screen_id)
{
if (_screen) {
diff --git a/client/screen_layer.h b/client/screen_layer.h
index cbcc5503..9b2ed7fa 100644
--- a/client/screen_layer.h
+++ b/client/screen_layer.h
@@ -45,6 +45,7 @@ public:
void invalidate();
uint64_t invalidate(const Rect& r, bool urgent = false);
void invalidate(const QRegion& r);
+ bool contains_point(int x, int y);
virtual void copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc) {}
@@ -61,8 +62,16 @@ public:
virtual void on_update_completion(uint64_t mark) {}
+ virtual bool pointer_test(int x, int y) { return false;}
+ virtual void on_pointer_enter(int x, int y, unsigned int buttons_state) {}
+ virtual void on_pointer_motion(int x, int y, unsigned int buttons_state) {}
+ virtual void on_pointer_leave() {}
+ virtual void on_mouse_button_press(int button, int buttons_state) {}
+ virtual void on_mouse_button_release(int button, int buttons_state) {}
+
private:
uint64_t invalidate_rect(const Rect& r, bool urgent);
+ void notify_changed();
private:
RedScreen* _screen;
diff --git a/client/windows/red_window.cpp b/client/windows/red_window.cpp
index 9365c69d..5c2d2da1 100644
--- a/client/windows/red_window.cpp
+++ b/client/windows/red_window.cpp
@@ -116,12 +116,15 @@ LRESULT CALLBACK RedWindow_p::WindowProc(HWND hWnd, UINT message, WPARAM wParam,
break;
}
case WM_MOUSEMOVE: {
+ Point origin = window->get_origin();
+ int x = LOWORD(lParam) - origin.x;
+ int y = HIWORD(lParam) - origin.y;
+ unsigned int buttons_state = to_red_mouse_state(wParam);
if (!window->_pointer_in_window) {
- window->on_pointer_enter();
+ window->on_pointer_enter(x, y, buttons_state);
+ } else {
+ window->get_listener().on_pointer_motion(x, y, buttons_state);
}
- Point origin = window->get_origin();
- window->get_listener().on_mouse_motion(LOWORD(lParam) - origin.x, HIWORD(lParam) - origin.y,
- to_red_mouse_state(wParam));
break;
}
case WM_MOUSELEAVE:
@@ -134,34 +137,40 @@ LRESULT CALLBACK RedWindow_p::WindowProc(HWND hWnd, UINT message, WPARAM wParam,
window->on_focus_out();
break;
case WM_LBUTTONDOWN:
- window->get_listener().on_button_press(REDC_MOUSE_LBUTTON, to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_press(REDC_MOUSE_LBUTTON,
+ to_red_mouse_state(wParam));
break;
case WM_LBUTTONUP:
- window->get_listener().on_button_release(REDC_MOUSE_LBUTTON, to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_release(REDC_MOUSE_LBUTTON,
+ to_red_mouse_state(wParam));
break;
case WM_RBUTTONDOWN:
- window->get_listener().on_button_press(REDC_MOUSE_RBUTTON, to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_press(REDC_MOUSE_RBUTTON,
+ to_red_mouse_state(wParam));
break;
case WM_RBUTTONUP:
- window->get_listener().on_button_release(REDC_MOUSE_RBUTTON, to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_release(REDC_MOUSE_RBUTTON,
+ to_red_mouse_state(wParam));
break;
case WM_MBUTTONDOWN:
- window->get_listener().on_button_press(REDC_MOUSE_MBUTTON, to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_press(REDC_MOUSE_MBUTTON,
+ to_red_mouse_state(wParam));
break;
case WM_MBUTTONUP:
- window->get_listener().on_button_release(REDC_MOUSE_MBUTTON, to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_release(REDC_MOUSE_MBUTTON,
+ to_red_mouse_state(wParam));
break;
case WM_MOUSEWHEEL:
if (HIWORD(wParam) & 0x8000) {
- window->get_listener().on_button_press(REDC_MOUSE_DBUTTON,
- to_red_mouse_state(wParam));
- window->get_listener().on_button_release(REDC_MOUSE_DBUTTON,
- to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_press(REDC_MOUSE_DBUTTON,
+ to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_release(REDC_MOUSE_DBUTTON,
+ to_red_mouse_state(wParam));
} else {
- window->get_listener().on_button_press(REDC_MOUSE_UBUTTON,
- to_red_mouse_state(wParam));
- window->get_listener().on_button_release(REDC_MOUSE_UBUTTON,
- to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_press(REDC_MOUSE_UBUTTON,
+ to_red_mouse_state(wParam));
+ window->get_listener().on_mouse_button_release(REDC_MOUSE_UBUTTON,
+ to_red_mouse_state(wParam));
}
break;
case WM_SYSKEYDOWN:
@@ -795,7 +804,7 @@ void RedWindow::on_focus_out()
get_listener().on_deactivate();
}
-void RedWindow::on_pointer_enter()
+void RedWindow::on_pointer_enter(int x, int y, unsigned int buttons_state)
{
if (_pointer_in_window) {
return;
@@ -810,7 +819,7 @@ void RedWindow::on_pointer_enter()
while (ShowCursor(FALSE) > -1);
}
_pointer_in_window = true;
- _listener.on_pointer_enter();
+ _listener.on_pointer_enter(x, y, buttons_state);
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp
index 2b4228a2..1d989b7c 100644
--- a/client/x11/red_window.cpp
+++ b/client/x11/red_window.cpp
@@ -726,9 +726,9 @@ void RedWindow_p::win_proc(XEvent& event)
if (event.xmotion.x >= 0 && event.xmotion.y >= 0 &&
event.xmotion.x < size.x && event.xmotion.y < size.y) {
Point origin = red_window->get_origin();
- red_window->get_listener().on_mouse_motion(event.xmotion.x - origin.x,
- event.xmotion.y - origin.y,
- to_red_buttons_state(event.xmotion.state));
+ 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;
}
@@ -758,7 +758,7 @@ void RedWindow_p::win_proc(XEvent& event)
DBG(0, "ButtonPress: invalid button %u", event.xbutton.button);
break;
}
- red_window->get_listener().on_button_press(button, state);
+ red_window->get_listener().on_mouse_button_press(button, state);
break;
}
case ButtonRelease: {
@@ -768,7 +768,7 @@ void RedWindow_p::win_proc(XEvent& event)
DBG(0, "ButtonRelease: invalid button %u", event.xbutton.button);
break;
}
- red_window->get_listener().on_button_release(button, state);
+ red_window->get_listener().on_mouse_button_release(button, state);
break;
}
case Expose: {
@@ -843,7 +843,9 @@ void RedWindow_p::win_proc(XEvent& event)
break;
case EnterNotify:
if (!red_window->_ignore_pointer) {
- red_window->on_pointer_enter();
+ Point origin = red_window->get_origin();
+ red_window->on_pointer_enter(event.xcrossing.x - origin.x, event.xcrossing.y - origin.y,
+ to_red_buttons_state(event.xmotion.state));
} else {
red_window->_shadow_pointer_state = true;
memcpy(&red_window->_shadow_pointer_event, &event, sizeof(XEvent));
@@ -1943,13 +1945,13 @@ void RedWindow::on_focus_out()
XPlatform::on_focus_out();
}
-void RedWindow::on_pointer_enter()
+void RedWindow::on_pointer_enter(int x, int y, unsigned int buttons_state)
{
if (_pointer_in_window) {
return;
}
_pointer_in_window = true;
- _listener.on_pointer_enter();
+ _listener.on_pointer_enter(x, y, buttons_state);
if (_focused && _trace_key_interception) {
do_start_key_interception();
}