diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/application.cpp | 37 | ||||
-rw-r--r-- | client/application.h | 3 | ||||
-rw-r--r-- | client/cursor_channel.cpp | 370 | ||||
-rw-r--r-- | client/cursor_channel.h | 28 | ||||
-rw-r--r-- | client/display_channel.cpp | 212 | ||||
-rw-r--r-- | client/display_channel.h | 28 | ||||
-rw-r--r-- | client/inputs_channel.cpp | 35 | ||||
-rw-r--r-- | client/inputs_channel.h | 5 | ||||
-rw-r--r-- | client/inputs_handler.h | 1 | ||||
-rw-r--r-- | client/red_client.cpp | 62 | ||||
-rw-r--r-- | client/red_client.h | 7 | ||||
-rw-r--r-- | client/red_window.h | 16 | ||||
-rw-r--r-- | client/screen.cpp | 302 | ||||
-rw-r--r-- | client/screen.h | 47 | ||||
-rw-r--r-- | client/screen_layer.cpp | 19 | ||||
-rw-r--r-- | client/screen_layer.h | 9 | ||||
-rw-r--r-- | client/windows/red_window.cpp | 49 | ||||
-rw-r--r-- | client/x11/red_window.cpp | 18 |
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 ®ion); - 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(); } |