spice-space-commit Mailing List for Spice Space (Page 4)
Brought to you by:
ykamay
You can subscribe to this list here.
2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(25) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2010 |
Jan
(81) |
Feb
(6) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Yaniv K. <yk...@re...> - 2010-01-03 15:36:58
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit ba04ac69c680389b8aa225c2ecac0d9fe9b7f0ff Author: Arnon Gilboa <ag...@ag...> Date: Sun Nov 15 19:02:40 2009 +0200 spice: show splash screen on disconnect only on debug diff --git a/client/application.cpp b/client/application.cpp index e53ad89..061dc37 100644 --- a/client/application.cpp +++ b/client/application.cpp @@ -61,8 +61,9 @@ void ConnectedEvent::response(AbstractProcessLoop& events_loop) void DisconnectedEvent::response(AbstractProcessLoop& events_loop) { Application* app = static_cast<Application*>(events_loop.get_owner()); +#ifdef RED_DEBUG app->show_splash(0); -#ifndef RED_DEBUG +#else app->do_quit(SPICEC_ERROR_CODE_SUCCESS); #endif } @@ -70,8 +71,9 @@ void DisconnectedEvent::response(AbstractProcessLoop& events_loop) void ConnectionErrorEvent::response(AbstractProcessLoop& events_loop) { Application* app = static_cast<Application*>(events_loop.get_owner()); +#ifdef RED_DEBUG app->show_splash(0); -#ifndef RED_DEBUG +#else app->do_quit(_error_code); #endif } |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:36:25
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit 6031cb8276ad56a41c31ba32df0fd5a6fa220c76 Author: Yaniv Kamay <yk...@re...> Date: Mon Nov 16 00:04:03 2009 +0200 client: change jitter buffer size to 300ms diff --git a/client/windows/playback.cpp b/client/windows/playback.cpp index 2e15ad9..b9e0025 100644 --- a/client/windows/playback.cpp +++ b/client/windows/playback.cpp @@ -21,8 +21,8 @@ #include "debug.h" -#define RING_SIZE_MS 160 -#define START_MARK_MS 80 +#define RING_SIZE_MS 380 +#define START_MARK_MS 300 #define LOW_MARK_MS 40 diff --git a/client/x11/playback.cpp b/client/x11/playback.cpp index d8f9766..5e796fd 100644 --- a/client/x11/playback.cpp +++ b/client/x11/playback.cpp @@ -19,6 +19,8 @@ #include "utils.h" #include "debug.h" +#define REING_SIZE_MS 300 + WavePlayer::WavePlayer(uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels) : _pcm (NULL) , _hw_params (NULL) @@ -117,7 +119,8 @@ bool WavePlayer::init(uint32_t sampels_per_sec, return false; } - snd_pcm_uframes_t buffer_size = (sampels_per_sec * 80 / 1000) / frame_size * frame_size; + snd_pcm_uframes_t buffer_size; + buffer_size = (sampels_per_sec * REING_SIZE_MS / 1000) / frame_size * frame_size; if ((err = snd_pcm_hw_params_set_buffer_size_near(_pcm, _hw_params, &buffer_size)) < 0) { LOG_ERROR("cannot set buffer size %s", snd_strerror(err)); |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:34:42
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit 0d93ce342c5b063c7cc36fcb7fb31fbecbbad608 Author: Yonit Halperin <yha...@re...> Date: Thu Nov 12 19:57:34 2009 +0200 spice client: sticky Alt activation when holding an Alt key Additional changes that were required for the feature: 1) focusing on the pointed window in full screen mode 2) In X11 - handling events that occur during keyboard ungrabbing 3) In X11 - handling Leave/Enter Notify events that occur during keyboard grabbing/ungrabbing 4) In X11 - fix for focus events that are handled in the wrong order (happens when focus events occur during grabbing the keyboard) 5) In X11 - ignoring key release events during key holding 6) In Windows - synchronizing keyboard release events that occured during a modal loop diff --git a/client/application.cpp b/client/application.cpp index 617934c..e53ad89 100644 --- a/client/application.cpp +++ b/client/application.cpp @@ -40,11 +40,15 @@ #include "quic.h" #include "mutex.h" #include "cmd_line_parser.h" +#include "rect.h" #include <log4cpp/BasicConfigurator.hh> #include <log4cpp/FileAppender.hh> #include <log4cpp/RollingFileAppender.hh> +#define STICKY_KEY_PIXMAP ALT_IMAGE_RES_ID +#define STICKY_KEY_TIMEOUT 750 + #ifdef CAIRO_CANVAS_CACH_IS_SHARED mutex_t cairo_surface_user_data_mutex; #endif @@ -94,6 +98,7 @@ public: void set_splash_mode(); void set_info_mode(); + void set_sticky(bool is_on); virtual void on_size_changed(); private: @@ -103,22 +108,29 @@ private: private: ImageFromRes _splash_pixmap; AlphaImageFromRes _info_pixmap; + AlphaImageFromRes _sticky_pixmap; Point _splash_pos; Point _info_pos; + Point _sticky_pos; + Rect _sticky_rect; bool _splash_mode; - Mutex _update_lock; + bool _sticky_on; + RecurciveMutex _update_lock; }; GUILayer::GUILayer() : ScreenLayer(SCREEN_LAYER_GUI, false) , _splash_pixmap (SPLASH_IMAGE_RES_ID) , _info_pixmap (INFO_IMAGE_RES_ID) + , _sticky_pixmap (STICKY_KEY_PIXMAP) , _splash_mode (false) + , _sticky_on (false) { } void GUILayer::draw_splash(const QRegion& dest_region, RedDrawable& dest) { + ASSERT(!_sticky_on); for (int i = 0; i < (int)dest_region.num_rects; i++) { Rect* r = &dest_region.rects[i]; dest.copy_pixels(_splash_pixmap, r->left - _splash_pos.x, r->top - _splash_pos.y, *r); @@ -129,13 +141,18 @@ void GUILayer::draw_info(const QRegion& dest_region, RedDrawable& dest) { for (int i = 0; i < (int)dest_region.num_rects; i++) { Rect* r = &dest_region.rects[i]; - dest.blend_pixels(_info_pixmap, r->left - _info_pos.x, r->top - _info_pos.y, *r); + /* is rect inside sticky region or info region? */ + if (_sticky_on && rect_intersects(*r, _sticky_rect)) { + dest.blend_pixels(_sticky_pixmap, r->left - _sticky_pos.x, r->top - _sticky_pos.y, *r); + } else { + dest.blend_pixels(_info_pixmap, r->left - _info_pos.x, r->top - _info_pos.y, *r); + } } } void GUILayer::copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc) { - Lock lock(_update_lock); + RecurciveLock lock(_update_lock); if (_splash_mode) { draw_splash(dest_region, dest_dc); } else { @@ -145,7 +162,7 @@ void GUILayer::copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc) void GUILayer::set_splash_mode() { - Lock lock(_update_lock); + RecurciveLock lock(_update_lock); Point size = _splash_pixmap.get_size(); Point screen_size = screen()->get_size(); Rect r; @@ -157,11 +174,12 @@ void GUILayer::set_splash_mode() _splash_mode = true; lock.unlock(); set_rect_area(r); + ASSERT(!_sticky_on); } void GUILayer::set_info_mode() { - Lock lock(_update_lock); + RecurciveLock lock(_update_lock); Point size = _info_pixmap.get_size(); Point screen_size = screen()->get_size(); Rect r; @@ -174,6 +192,33 @@ void GUILayer::set_info_mode() _splash_mode = false; lock.unlock(); set_rect_area(r); + + set_sticky(_sticky_on); +} + +void GUILayer::set_sticky(bool is_on) +{ + RecurciveLock lock(_update_lock); + if (!_sticky_on && !is_on) { + return; + } + + Point size = _sticky_pixmap.get_size(); + Point screen_size = screen()->get_size(); + + _sticky_on = is_on; + if (_sticky_on) { + _sticky_pos.x = (screen_size.x - size.x) / 2; + _sticky_pos.y = screen_size.y * 2 / 3; + _sticky_rect.left = _sticky_pos.x; + _sticky_rect.top = _sticky_pos.y; + _sticky_rect.right = _sticky_rect.left + size.x; + _sticky_rect.bottom = _sticky_rect.top + size.y; + add_rect_area(_sticky_rect); + invalidate(); + } else { + remove_rect_area(_sticky_rect); + } } void GUILayer::on_size_changed() @@ -181,6 +226,20 @@ void GUILayer::on_size_changed() set_info_mode(); } +void StickyKeyTimer::response(AbstractProcessLoop& events_loop) +{ + Application* app = (Application*)events_loop.get_owner(); + StickyInfo* sticky_info = &app->_sticky_info; + ASSERT(app->is_sticky_trace_key(sticky_info->key)); + ASSERT(app->_key_table[sticky_info->key ].press); + ASSERT(sticky_info->key_first_down); + ASSERT(sticky_info->key_down); + sticky_info->sticky_mode = true; + DBG(0, "ON sticky"); + app->_gui_layer->set_sticky(true); + app->deactivate_interval_timer(this); +} + static InputsHandler default_inputs_handler; enum AppCommands { @@ -211,6 +270,8 @@ Application::Application() , _inputs_handler (&default_inputs_handler) , _monitors (NULL) , _title (L"SPICEc:%d") + , _splash_mode (true) + , _sys_key_intercept_mode (false) { DBG(0, ""); Platform::set_process_loop(*this); @@ -247,6 +308,13 @@ Application::Application() #endif , _commands_map)); _hot_keys = parser->get(); + + _sticky_info.trace_is_on = false; + _sticky_info.sticky_mode = false; + _sticky_info.key_first_down = false; + _sticky_info.key_down = false; + _sticky_info.key = REDKEY_INVALID; + _sticky_info.timer.reset(new StickyKeyTimer()); } Application::~Application() @@ -472,6 +540,7 @@ void Application::init_pause_scan_code() void Application::init_key_table() { memset(_key_table, 0, sizeof(_key_table)); + _num_keys_pressed = 0; init_scan_code(REDKEY_ESCAPE); init_scan_code(REDKEY_1); init_scan_code(REDKEY_2); @@ -607,12 +676,13 @@ inline uint32_t Application::get_break_scan_code(RedKey key) void Application::unpress_all() { + reset_sticky(); for (int i = 0; i < REDKEY_NUM_KEYS; i++) { if (_key_table[i].press) { uint32_t scan_code = get_break_scan_code((RedKey)i); ASSERT(scan_code); _inputs_handler->on_key_up(scan_code); - _key_table[i].press = false; + unpress_key((RedKey)i); } } } @@ -791,6 +861,57 @@ static void show_red_key(RedKey key) #endif +bool Application::press_key(RedKey key) +{ + if (_key_table[key].press) { + return true; + } else { + _key_table[key].press = true; + _num_keys_pressed++; + return false; + } +} + +bool Application::unpress_key(RedKey key) +{ + ASSERT(!_sticky_info.key_down || !is_sticky_trace_key(key)); + + if (_key_table[key].press) { + _key_table[key].press = false; + _num_keys_pressed--; + ASSERT(_num_keys_pressed >= 0); + return true; + } else { + return false; + } +} + +inline bool Application::is_sticky_trace_key(RedKey key) +{ + return ((key == REDKEY_L_ALT) || (key == REDKEY_R_ALT)); +} + +void Application::reset_sticky() +{ + _sticky_info.trace_is_on = !_splash_mode && _sys_key_intercept_mode; + _sticky_info.key_first_down = false; + deactivate_interval_timer(*_sticky_info.timer); + if (_sticky_info.sticky_mode) { + ASSERT(_key_table[_sticky_info.key].press); + // if it is physically down, we shouldn't unpress it + if (!_sticky_info.key_down) { + do_on_key_up(_sticky_info.key); + } + _sticky_info.sticky_mode = false; + DBG(0, "OFF sticky"); + _gui_layer->set_sticky(false); + } + _sticky_info.key_down = false; + + _sticky_info.key = REDKEY_INVALID; + +} + void Application::on_key_down(RedKey key) { if (key <= 0 || key >= REDKEY_NUM_KEYS) { @@ -802,7 +923,30 @@ void Application::on_key_down(RedKey key) LOG_WARN("no make code for %d", key); return; } - _key_table[key].press = true; + + bool was_pressed = press_key(key); + if (_sticky_info.trace_is_on) { + if (key == _sticky_info.key) { + _sticky_info.key_down = true; + } + + if (!_sticky_info.sticky_mode) { + // during tracing (traced key was pressed and no keyboard event has occured till now) + if (_sticky_info.key_first_down) { + ASSERT(_sticky_info.key != REDKEY_INVALID); + if (key != _sticky_info.key) { + reset_sticky(); + } + } else if (is_sticky_trace_key(key) && (_num_keys_pressed == 1) && !was_pressed) { + ASSERT(_sticky_info.key == REDKEY_INVALID); + // start tracing + _sticky_info.key = key; + _sticky_info.key_first_down = true; + _sticky_info.key_down = true; + activate_interval_timer(*_sticky_info.timer, STICKY_KEY_TIMEOUT); + } + } + } int command = get_hotkeys_commnad(); if (command != APP_CMD_INVALID) { @@ -814,17 +958,18 @@ void Application::on_key_down(RedKey key) if (!_active_screen->intercepts_sys_key() && (key == REDKEY_LEFT_CMD || key == REDKEY_RIGHT_CMD || key == REDKEY_MENU || _key_table[REDKEY_L_ALT].press)) { - _key_table[key].press = false; + unpress_key(key); return; } - if ((_key_table[REDKEY_L_CTRL].press || _key_table[REDKEY_R_CTRL].press) && - (_key_table[REDKEY_L_ALT].press || _key_table[REDKEY_R_ALT].press)) { + if (!_sticky_info.sticky_mode && + ((_key_table[REDKEY_L_CTRL].press || _key_table[REDKEY_R_CTRL].press) && + (_key_table[REDKEY_L_ALT].press || _key_table[REDKEY_R_ALT].press))) { if (key == REDKEY_END || key == REDKEY_PAD_1) { - _key_table[key].press = false; + unpress_key(key); _inputs_handler->on_key_down(get_make_scan_code(REDKEY_DELETE)); _inputs_handler->on_key_up(get_break_scan_code(REDKEY_DELETE)); } else if (key == REDKEY_DELETE || key == REDKEY_PAD_POINT) { - _key_table[key].press = false; + unpress_key(key); return; } } @@ -833,12 +978,9 @@ void Application::on_key_down(RedKey key) _inputs_handler->on_key_down(scan_code); } -void Application::on_key_up(RedKey key) +void Application::do_on_key_up(RedKey key) { - if (key < 0 || key >= REDKEY_NUM_KEYS || !_key_table[key].press) { - return; - } - _key_table[key].press = false; + unpress_key(key); uint32_t scan_code = get_break_scan_code(key); if (!scan_code) { LOG_WARN("no break code for %d", key); @@ -847,9 +989,43 @@ void Application::on_key_up(RedKey key) _inputs_handler->on_key_up(scan_code); } +void Application::on_key_up(RedKey key) +{ + if(key < 0 || key >= REDKEY_NUM_KEYS || !_key_table[key].press) { + return; + } + + if (_sticky_info.trace_is_on) { + ASSERT(_sticky_info.sticky_mode || (key == _sticky_info.key) || + (_sticky_info.key == REDKEY_INVALID)); + if (key == _sticky_info.key) { + _sticky_info.key_down = false; + if (_sticky_info.key_first_down) { + _sticky_info.key_first_down = false; + if (!_sticky_info.sticky_mode) { + reset_sticky(); + } else { + return; // ignore the sticky-key first release + } + } + } + + if (_sticky_info.sticky_mode) { + RedKey old_sticky_key = _sticky_info.key; + reset_sticky(); + if (key == old_sticky_key) { + return; // no need to send key_up twice + } + } + } + + do_on_key_up(key); + } + void Application::on_deactivate_screen(RedScreen* screen) { if (_active_screen == screen) { + _sys_key_intercept_mode = false; release_capture(); _active_screen = NULL; } @@ -857,9 +1033,26 @@ void Application::on_deactivate_screen(RedScreen* screen) void Application::on_activate_screen(RedScreen* screen) { + ASSERT(!_active_screen || (_active_screen == screen)); _active_screen = screen; } +void Application::on_start_screen_key_interception(RedScreen* screen) +{ + ASSERT(screen == _active_screen); + + _sys_key_intercept_mode = true; + reset_sticky(); +} + +void Application::on_stop_screen_key_interception(RedScreen* screen) +{ + ASSERT(screen == _active_screen); + + _sys_key_intercept_mode = false; + reset_sticky(); +} + void Application::on_app_activated() { _active = true; @@ -996,6 +1189,7 @@ void Application::show_full_screen() void Application::enter_full_screen() { + LOG_INFO(""); _changing_screens = true; release_capture(); assign_monitors(); @@ -1014,6 +1208,7 @@ void Application::exit_full_screen() if (!_full_screen) { return; } + LOG_INFO(""); release_capture(); for (int i = 0; i < (int)_screens.size(); i++) { if (_screens[i]) { @@ -1087,7 +1282,9 @@ void Application::show_splash(int screen_id) if (screen_id != 0) { return; } + _splash_mode = true; release_capture(); + ASSERT(!_sticky_info.trace_is_on); (*_gui_layer).set_splash_mode(); } @@ -1096,7 +1293,9 @@ void Application::hide_splash(int screen_id) if (screen_id != 0) { return; } + _splash_mode = false; (*_gui_layer).set_info_mode(); + reset_sticky(); } uint32_t Application::get_mouse_mode() diff --git a/client/application.h b/client/application.h index 91afb54..c576dba 100644 --- a/client/application.h +++ b/client/application.h @@ -90,6 +90,25 @@ enum CanvasOption { #endif }; +class StickyKeyTimer: public Timer { +public: + virtual void response(AbstractProcessLoop& events_loop); +}; + +typedef struct StickyInfo { + bool trace_is_on; + bool sticky_mode; + bool key_first_down; // True when (1) a potential sticky key is pressed, + // and none of the other keys are pressed and (2) in the moment + // of pressing, _sticky_mode is false. When the key is up + // for the first time, it is set to false. + bool key_down; // The physical state of the sticky key. Valid only till + // stickiness is removed. + RedKey key; // the key that is currently being traced, or, + // if _sticky mode is on, the sticky key + AutoRef<StickyKeyTimer> timer; +} StickyInfo; + class Application : public ProcessLoop, public Platform::EventListener, public Platform::DisplayModeListner, @@ -114,6 +133,8 @@ public: void on_key_up(RedKey key); void on_deactivate_screen(RedScreen* screen); void on_activate_screen(RedScreen* screen); + void on_start_screen_key_interception(RedScreen* screen); + void on_stop_screen_key_interception(RedScreen* screen); virtual void on_app_activated(); virtual void on_app_deactivated(); virtual void on_monitors_change(); @@ -180,6 +201,13 @@ private: int get_hotkeys_commnad(); bool is_key_set_pressed(const HotkeySet& key_set); bool is_cad_pressed(); + void do_on_key_up(RedKey key); + + // returns the press value before operation (i.e., if it was already pressed) + bool press_key(RedKey key); + bool unpress_key(RedKey key); + void reset_sticky(); + static bool is_sticky_trace_key(RedKey key); static void init_logger(); static void init_globals(); @@ -188,6 +216,7 @@ private: friend class ConnectionErrorEvent; friend class MonitorsQuery; friend class AutoAbort; + friend class StickyKeyTimer; private: RedClient _client; @@ -201,12 +230,16 @@ private: int _exit_code; RedScreen* _active_screen; KeyInfo _key_table[REDKEY_NUM_KEYS]; + int _num_keys_pressed; HotKeys _hot_keys; CommandsMap _commands_map; std::auto_ptr<GUILayer> _gui_layer; InputsHandler* _inputs_handler; const MonitorsList* _monitors; std::wstring _title; + bool _splash_mode; + bool _sys_key_intercept_mode; + StickyInfo _sticky_info; std::vector<int> _canvas_types; AutoRef<Menu> _app_menu; }; diff --git a/client/red_window.h b/client/red_window.h index e356576..0d3e781 100644 --- a/client/red_window.h +++ b/client/red_window.h @@ -106,7 +106,8 @@ private: bool _cursor_visible; bool _focused; bool _pointer_in_window; - bool _key_interception; + bool _trace_key_interception; + bool _key_interception_on; Menu* _menu; friend class RedWindow_p; diff --git a/client/screen.cpp b/client/screen.cpp index 8b7ee28..bbc76e7 100644 --- a/client/screen.cpp +++ b/client/screen.cpp @@ -93,11 +93,13 @@ RedScreen::RedScreen(Application& owner, int id, const std::wstring& name, int w _window.set_menu(*menu); AutoRef<Icon> icon(Platform::load_icon(RED_ICON_RES_ID)); _window.set_icon(*icon); + _window.start_key_interception(); } RedScreen::~RedScreen() { bool captured = is_captured(); + _window.stop_key_interception(); relase_inputs(); destroy_composit_area(); _owner.deactivate_interval_timer(*_update_timer); @@ -435,9 +437,6 @@ void RedScreen::capture_inputs() reset_mouse_pos(); _window.cupture_mouse(); } -#ifndef NO_KEY_GRAB - _window.start_key_interception(); -#endif _captured = true; } @@ -446,9 +445,6 @@ void RedScreen::relase_inputs() if (!_captured) { return; } -#ifndef NO_KEY_GRAB - _window.stop_key_interception(); -#endif _captured = false; _window.release_mouse(); if (_owner.get_mouse_mode() == RED_MOUSE_MODE_SERVER) { @@ -576,6 +572,11 @@ 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(); + } } } @@ -584,6 +585,18 @@ void RedScreen::on_pointer_leave() _pointer_location = POINTER_OUTSIDE_WINDOW; } +void RedScreen::on_start_key_interception() +{ + _key_interception = true; + _owner.on_start_screen_key_interception(this); +} + +void RedScreen::on_stop_key_interception() +{ + _key_interception = false; + _owner.on_stop_screen_key_interception(this); +} + void RedScreen::enter_modal_loop() { _forec_update_timer++; diff --git a/client/screen.h b/client/screen.h index 957cece..b191d09 100644 --- a/client/screen.h +++ b/client/screen.h @@ -136,8 +136,8 @@ private: virtual void on_activate(); virtual void on_pointer_enter(); virtual void on_pointer_leave(); - virtual void on_start_key_interception() { _key_interception = true;} - virtual void on_stop_key_interception() { _key_interception = false;} + virtual void on_start_key_interception(); + virtual void on_stop_key_interception(); virtual void enter_modal_loop(); virtual void exit_modal_loop(); diff --git a/client/windows/red_window.cpp b/client/windows/red_window.cpp index 01d82e5..ab1aa15 100644 --- a/client/windows/red_window.cpp +++ b/client/windows/red_window.cpp @@ -25,6 +25,8 @@ #include "win_platform.h" #include "platform_utils.h" +#include <list> + #define NATIVE_CAPTION_STYLE (WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX) extern HINSTANCE instance; @@ -33,7 +35,11 @@ static ATOM class_atom = 0; static const LPCWSTR win_class_name = L"redc_wclass"; static HWND focus_window = NULL; static HHOOK low_keyboard_hook = NULL; +static HHOOK msg_filter_hook = NULL; +typedef std::list<RedKey> KeysList; +static KeysList filtered_up_keys; +static LRESULT CALLBACK MessageFilterProc(int nCode, WPARAM wParam, LPARAM lParam); static inline int to_red_mouse_state(WPARAM wParam) { @@ -78,6 +84,16 @@ static int menu_cmd_to_app(WPARAM wparam) return 0; } +static inline void send_filtered_keys(RedWindow* window) +{ + KeysList::iterator iter; + + for (iter = filtered_up_keys.begin(); iter != filtered_up_keys.end(); iter++) { + window->get_listener().on_key_release(*iter); + } + filtered_up_keys.clear(); +} + LRESULT CALLBACK RedWindow_p::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RedWindow* window = (RedWindow*)GetWindowLong(hWnd, GWL_USERDATA); @@ -153,7 +169,7 @@ LRESULT CALLBACK RedWindow_p::WindowProc(HWND hWnd, UINT message, WPARAM wParam, RedKey key = translate_key(wParam, HIWORD(lParam) & 0xff, (lParam & (1 << 24)) != 0); window->get_listener().on_key_press(key); // Allow Windows to translate Alt-F4 to WM_CLOSE message. - if (!window->_key_interception) { + if (!window->_key_interception_on) { return DefWindowProc(hWnd, message, wParam, lParam); } break; @@ -164,13 +180,6 @@ LRESULT CALLBACK RedWindow_p::WindowProc(HWND hWnd, UINT message, WPARAM wParam, window->get_listener().on_key_release(key); break; } - case WM_ACTIVATE: - if (LOWORD(wParam) == WA_INACTIVE) { - window->get_listener().on_deactivate(); - } else { - window->get_listener().on_activate(); - } - break; case WM_DESTROY: PostQuitMessage(0); break; @@ -190,13 +199,25 @@ LRESULT CALLBACK RedWindow_p::WindowProc(HWND hWnd, UINT message, WPARAM wParam, return DefWindowProc(hWnd, message, wParam, lParam); case WM_ENTERSIZEMOVE: case WM_ENTERMENULOOP: + ASSERT(filtered_up_keys.empty()); + DBG(0, "enter modal"); window->get_listener().enter_modal_loop(); WinPlatform::enter_modal_loop(); + if (msg_filter_hook) { + LOG_WARN("entering modal loop while filter hook is active"); + UnhookWindowsHookEx(msg_filter_hook); + } + msg_filter_hook = SetWindowsHookEx(WH_MSGFILTER, MessageFilterProc, + GetModuleHandle(NULL), GetCurrentThreadId()); return DefWindowProc(hWnd, message, wParam, lParam); case WM_EXITSIZEMOVE: case WM_EXITMENULOOP: + DBG(0, "exit modal"); window->get_listener().exit_modal_loop(); WinPlatform::exit_modal_loop(); + UnhookWindowsHookEx(msg_filter_hook); + msg_filter_hook = NULL; + send_filtered_keys(window); return DefWindowProc(hWnd, message, wParam, lParam); case WM_SETCURSOR: if (!window->_pointer_in_window) { @@ -324,7 +345,8 @@ RedWindow::RedWindow(RedWindow::Listener& listener, int screen_id) , _cursor_visible (true) , _focused (false) , _pointer_in_window (false) - , _key_interception (false) + , _trace_key_interception (false) + , _key_interception_on (false) , _menu (NULL) { RECT win_rect; @@ -486,6 +508,7 @@ void RedWindow::resize(int width, int height) void RedWindow::activate() { SetActiveWindow(_win); + SetFocus(_win); } void RedWindow::minimize() @@ -667,32 +690,32 @@ static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lP void RedWindow::do_start_key_interception() { + _key_interception_on = true; + _listener.on_start_key_interception(); if (low_keyboard_hook) { return; } low_keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0); - _listener.on_start_key_interception(); } void RedWindow::do_stop_key_interception() { + _key_interception_on = false; + _listener.on_stop_key_interception(); if (!low_keyboard_hook) { return; } - UnhookWindowsHookEx(low_keyboard_hook); low_keyboard_hook = NULL; - _listener.on_stop_key_interception(); } void RedWindow::start_key_interception() { - if (_key_interception) { + if (_trace_key_interception) { return; } - _key_interception = true; - focus_window = _win; + _trace_key_interception = true; if (_focused && _pointer_in_window) { do_start_key_interception(); } @@ -700,11 +723,11 @@ void RedWindow::start_key_interception() void RedWindow::stop_key_interception() { - if (!_key_interception) { + if (!_trace_key_interception) { return; } - _key_interception = false; - if (_focused && _pointer_in_window) { + _trace_key_interception = false; + if (_key_interception_on) { do_stop_key_interception(); } } @@ -743,7 +766,9 @@ void RedWindow::unset_type_gl() void RedWindow::on_focus_in() { _focused = true; - if (_pointer_in_window && _key_interception) { + focus_window = _win; + get_listener().on_activate(); + if (_pointer_in_window && _trace_key_interception) { do_start_key_interception(); } } @@ -753,8 +778,13 @@ void RedWindow::on_focus_out() if (!_focused) { return; } + _focused = false; - do_stop_key_interception(); + + if (_key_interception_on) { + do_stop_key_interception(); + } + get_listener().on_deactivate(); } void RedWindow::on_pointer_enter() @@ -762,6 +792,7 @@ void RedWindow::on_pointer_enter() if (_pointer_in_window) { return; } + if (_cursor_visible) { if (_local_cursor) { _local_cursor->set(_win); @@ -780,7 +811,7 @@ void RedWindow::on_pointer_enter() if (!TrackMouseEvent(&tme)) { THROW("track mouse event failed"); } - if (_focused && _key_interception) { + if (_focused && _trace_key_interception) { do_start_key_interception(); } } @@ -795,7 +826,7 @@ void RedWindow::on_pointer_leave() } _pointer_in_window = false; _listener.on_pointer_leave(); - if (_focused && _key_interception) { + if (_key_interception_on) { do_stop_key_interception(); } } @@ -933,3 +964,23 @@ void RedWindow::set_menu(Menu* menu) insert_menu(_menu, _sys_menu, _commands_map); } +static LRESULT CALLBACK MessageFilterProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode >= 0) + { + MSG* msg = (MSG*)lParam; + + switch (msg->message) { + case WM_SYSKEYUP: + case WM_KEYUP: { + RedKey key = translate_key(msg->wParam, HIWORD(msg->lParam) & 0xff, + (msg->lParam & (1 << 24)) != 0); + filtered_up_keys.push_back(key); + break; + } + default: + break; + } + } + return CallNextHookEx(NULL, nCode, wParam, lParam); +} diff --git a/client/windows/redc.rc b/client/windows/redc.rc index cf0ef17..2af4ac9 100644 --- a/client/windows/redc.rc +++ b/client/windows/redc.rc @@ -54,6 +54,7 @@ END SPLASH_IMAGE_RES_ID BITMAP "splash.bmp" INFO_IMAGE_RES_ID BITMAP "static_title.bmp" +ALT_IMAGE_RES_ID BITMAP "sticky_alt.bmp" ///////////////////////////////////////////////////////////////////////////// // diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj index dac0fff..ed221ba 100644 --- a/client/windows/redc.vcproj +++ b/client/windows/redc.vcproj @@ -598,6 +598,10 @@ RelativePath=".\static_title.bmp" > </File> + <File + RelativePath=".\sticky_alt.bmp" + > + </File> </Filter> </Files> <Globals> diff --git a/client/windows/resource.h b/client/windows/resource.h index 51ff7f2..c6a1a61 100644 --- a/client/windows/resource.h +++ b/client/windows/resource.h @@ -1,19 +1,20 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by redc.rc -// -#define RED_ICON_RES_ID 5 -#define SPLASH_IMAGE_RES_ID 101 -#define INFO_IMAGE_RES_ID 102 -#define IDI_ICON_APPLICATION 103 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 106 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by redc.rc +// +#define RED_ICON_RES_ID 5 +#define SPLASH_IMAGE_RES_ID 101 +#define INFO_IMAGE_RES_ID 102 +#define IDI_ICON_APPLICATION 103 +#define ALT_IMAGE_RES_ID 104 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/client/windows/sticky_alt.bmp b/client/windows/sticky_alt.bmp new file mode 100644 index 0000000..4013472 Binary files /dev/null and b/client/windows/sticky_alt.bmp differ diff --git a/client/x11/images/alt_image.c b/client/x11/images/alt_image.c new file mode 100644 index 0000000..7968339 --- /dev/null +++ b/client/x11/images/alt_image.c @@ -0,0 +1,735 @@ +static const struct { + uint32_t width; + uint32_t height; + uint8_t pixel_data[17496]; +} _alt_image = { 81, 54, { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x16,0x16,0x16,0x2d,0x39,0x39,0x39,0x70,0x48,0x48,0x48,0x8e,0x58,0x58,0x58,0xae,0x68,0x68,0x68,0xcd, + 0x78,0x78,0x78,0xec,0x82,0x82,0x82,0xff,0x81,0x81,0x81,0xfe,0x80,0x80,0x80,0xfd,0x80,0x80,0x80,0xfc,0x7f,0x7f,0x7f,0xfb, + 0x7f,0x7f,0x7f,0xfa,0x7e,0x7e,0x7e,0xf9,0x7e,0x7e,0x7e,0xf8,0x7e,0x7e,0x7e,0xf8,0x7d,0x7d,0x7d,0xf7,0x7d,0x7d,0x7d,0xf6, + 0x7c,0x7c,0x7c,0xf5,0x7c,0x7c,0x7c,0xf4,0x7b,0x7b,0x7b,0xf3,0x7b,0x7b,0x7b,0xf2,0x7a,0x7a,0x7a,0xf1,0x7a,0x7a,0x7a,0xf0, + 0x79,0x79,0x79,0xef,0x79,0x79,0x79,0xee,0x78,0x78,0x78,0xed,0x78,0x78,0x78,0xec,0x77,0x77,0x77,0xeb,0x77,0x77,0x77,0xea, + 0x76,0x76,0x76,0xe9,0x76,0x76,0x76,0xe8,0x75,0x75,0x75,0xe7,0x75,0x75,0x75,0xe6,0x74,0x74,0x74,0xe5,0x74,0x74,0x74,0xe4, + 0x74,0x74,0x74,0xe4,0x73,0x73,0x73,0xe3,0x73,0x73,0x73,0xe2,0x72,0x72,0x72,0xe1,0x72,0x72,0x72,0xe0,0x71,0x71,0x71,0xdf, + 0x71,0x71,0x71,0xde,0x70,0x70,0x70,0xdd,0x70,0x70,0x70,0xdc,0x6f,0x6f,0x6f,0xdb,0x6f,0x6f,0x6f,0xda,0x6e,0x6e,0x6e,0xd9, + 0x6e,0x6e,0x6e,0xd8,0x6d,0x6d,0x6d,0xd7,0x6d,0x6d,0x6d,0xd6,0x6c,0x6c,0x6c,0xd5,0x6c,0x6c,0x6c,0xd4,0x6b,0x6b,0x6b,0xd3, + 0x6b,0x6b,0x6b,0xd2,0x6a,0x6a,0x6a,0xd1,0x6a,0x6a,0x6a,0xd1,0x69,0x69,0x69,0xcf,0x61,0x61,0x61,0xc0,0x60,0x60,0x60,0xca, + 0x64,0x64,0x64,0xe2,0x5b,0x5b,0x5b,0xd3,0x52,0x52,0x52,0xc2,0x47,0x47,0x47,0xad,0x33,0x33,0x33,0x87,0x19,0x19,0x19,0x55, + 0x0b,0x0b,0x0b,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x23,0x53,0x53,0x53,0xa4,0x80,0x80,0x80,0xfd,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x79,0x79,0x79,0xff,0x64,0x64,0x64,0xff,0x3f,0x3f,0x3f,0xc4,0x1c,0x1c,0x1c,0x5d, + 0x02,0x02,0x02,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x0a,0x0a,0x15,0x4c,0x4c,0x4c,0x96,0x7f,0x7f,0x7f,0xfa, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x81,0x81,0x81,0xff,0x70,0x70,0x70,0xff,0x4d,0x4d,0x4d,0xf1,0x2c,0x2c,0x2c,0x95,0x03,0x03,0x03,0x0a, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x02, + 0x62,0x62,0x62,0xc2,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x7b,0x7b,0x7b,0xff,0x54,0x54,0x54,0xff,0x3b,0x3b,0x3b,0xc5,0x04,0x04,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x3e,0x3e,0x7b,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x83,0x7f,0x80,0xee,0x88,0x7d,0x7e,0xce,0x88,0x7c,0x7c,0xc2,0x8a,0x7a,0x7c,0xb7, + 0x8c,0x7a,0x7b,0xac,0x8d,0x79,0x7a,0xa5,0x8c,0x79,0x7a,0xa5,0x8d,0x79,0x7b,0xa6,0x8c,0x79,0x7b,0xa6,0x8c,0x79,0x7b,0xa6, + 0x8c,0x79,0x7b,0xa7,0x8c,0x79,0x7b,0xa7,0x8c,0x79,0x7a,0xa7,0x8c,0x79,0x7a,0xa7,0x8c,0x79,0x7b,0xa8,0x8c,0x79,0x7b,0xa8, + 0x8d,0x79,0x7b,0xa9,0x8c,0x79,0x7b,0xa9,0x8c,0x79,0x7b,0xa9,0x8c,0x7a,0x7b,0xaa,0x8c,0x79,0x7b,0xaa,0x8c,0x79,0x7b,0xaa, + 0x8c,0x7a,0x7b,0xab,0x8c,0x79,0x7b,0xab,0x8c,0x79,0x7b,0xab,0x8c,0x7a,0x7b,0xac,0x8c,0x79,0x7b,0xac,0x8b,0x79,0x7b,0xac, + 0x8c,0x7a,0x7b,0xad,0x8b,0x79,0x7b,0xad,0x8b,0x79,0x7b,0xad,0x8b,0x7a,0x7b,0xae,0x8b,0x79,0x7b,0xae,0x8c,0x7a,0x7c,0xaf, + 0x8c,0x7a,0x7b,0xaf,0x8c,0x7a,0x7b,0xaf,0x8b,0x7a,0x7b,0xaf,0x8c,0x7a,0x7c,0xb0,0x8b,0x7a,0x7b,0xb0,0x8b,0x7a,0x7b,0xb0, + 0x8c,0x7a,0x7c,0xb1,0x8b,0x7a,0x7b,0xb1,0x8b,0x7a,0x7b,0xb1,0x8b,0x7a,0x7c,0xb2,0x8b,0x7a,0x7c,0xb2,0x8a,0x7a,0x7b,0xb2, + 0x8b,0x7a,0x7c,0xb3,0x8a,0x7a,0x7c,0xb3,0x8a,0x7a,0x7b,0xb3,0x8b,0x7a,0x7c,0xb4,0x8b,0x7a,0x7c,0xb4,0x8b,0x7a,0x7c,0xb5, + 0x8b,0x7a,0x7c,0xb5,0x8b,0x7a,0x7c,0xb5,0x8b,0x7a,0x7c,0xb6,0x8a,0x7a,0x7c,0xb6,0x8a,0x7b,0x7c,0xbc,0x8c,0x7e,0x80,0xcc, + 0x8d,0x80,0x82,0xd8,0x8c,0x82,0x83,0xe0,0x8c,0x83,0x84,0xe7,0x89,0x83,0x84,0xf1,0x82,0x82,0x82,0xfe,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x7b,0x7b,0x7b,0xff,0x4f,0x4f,0x4f,0xff, + 0x3a,0x3a,0x3a,0xc3,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0x1b,0x1b,0x36,0x7f,0x7f,0x7f,0xfb, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x83,0x80,0x80,0xf3,0x89,0x7c,0x7d,0xc5,0x8c,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8c,0x79,0x7b,0xac,0x87,0x7d,0x7e,0xcd,0x83,0x81,0x81,0xf2,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x69,0x69,0x69,0xff,0x4d,0x4d,0x4d,0xff,0x1c,0x1c,0x1c,0x5f,0x00,0x00,0x00,0x00, + 0x02,0x02,0x02,0x04,0x6f,0x6f,0x6f,0xdb,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x83,0x81,0x81,0xf7, + 0x8c,0x7a,0x7b,0xad,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8c,0x79,0x7b,0xa7,0x86,0x7f,0x7f,0xe1,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x81,0x81,0x81,0xff, + 0x50,0x50,0x50,0xff,0x44,0x44,0x44,0xe4,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x81,0x81,0x81,0xfe,0x89,0x7b,0x7c,0xbc,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8c,0x79,0x7b,0xa9,0x83,0x81,0x81,0xf6, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x5c,0x5c,0x5c,0xff,0x4d,0x4d,0x4d,0xff,0x0b,0x0b,0x0b,0x26, + 0x33,0x33,0x33,0x65,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x85,0x7f,0x7f,0xe2,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x86,0x7e,0x7f,0xda,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x68,0x68,0x68,0xff,0x4d,0x4d,0x4d,0xff,0x1d,0x1d,0x1d,0x61,0x4f,0x4f,0x4f,0x9b,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x87,0x7d,0x7e,0xce,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x7a,0x69,0x6b,0xb0,0x4c,0x40,0x42,0xcf,0x4c,0x40,0x42,0xcf,0x4c,0x40,0x42,0xcf, + 0x4c,0x40,0x42,0xcf,0x4c,0x40,0x42,0xcf,0x4c,0x40,0x42,0xcf,0x82,0x6f,0x71,0xac,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x88,0x7b,0x7d,0xc4, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x75,0x75,0x75,0xff,0x4d,0x4d,0x4d,0xff,0x2f,0x2f,0x2f,0x9d, + 0x6a,0x6a,0x6a,0xd0,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x8a,0x7b,0x7d,0xbc,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x75,0x64,0x67,0xb4,0x6f,0x5f,0x60,0xb8,0x6f,0x5f,0x60,0xb8,0x6f,0x5f,0x60,0xb8, + 0x6f,0x5f,0x60,0xb8,0x6f,0x5f,0x60,0xb8,0x6f,0x5f,0x60,0xb8,0x6f,0x5f,0x60,0xb8,0x7c,0x6a,0x6c,0xb0,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x73,0x63,0x64,0xb6, + 0x2e,0x28,0x28,0xe2,0x95,0x92,0x95,0xf4,0x95,0x92,0x95,0xf4,0x95,0x92,0x95,0xf4,0x95,0x92,0x95,0xf4,0x95,0x92,0x95,0xf4, + 0xb2,0xab,0xad,0xe1,0x9f,0x90,0x92,0xbd,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8c,0x7a,0x7b,0xaf,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x80,0x80,0x80,0xff,0x4e,0x4e,0x4e,0xff,0x41,0x41,0x41,0xd9,0x7f,0x7f,0x7f,0xfb,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x8c,0x7a,0x7b,0xaa,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x89,0x75,0x77,0xa7,0x32,0x2a,0x2b,0xdf, + 0x51,0x4c,0x4e,0xe8,0x6b,0x68,0x69,0xed,0x6b,0x68,0x69,0xed,0x6b,0x68,0x69,0xed,0x6b,0x68,0x69,0xed,0x6b,0x68,0x69,0xed, + 0x6b,0x68,0x69,0xed,0x78,0x73,0x74,0xe4,0xa3,0x96,0x98,0xc3,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x73,0x63,0x64,0xb6,0x2e,0x28,0x28,0xe2,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xb6,0xb0,0xb2,0xe5,0xa0,0x92,0x94,0xbe,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x80,0x6e,0x70,0xac,0x80,0x6e,0x70,0xac, + 0x80,0x6e,0x70,0xac,0x80,0x6e,0x70,0xac,0x80,0x6e,0x70,0xac,0x80,0x6e,0x70,0xac,0x87,0x74,0x76,0xa8,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x83,0x80,0x80,0xf5,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x53,0x53,0x53,0xff,0x4d,0x4d,0x4d,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x6f,0x60,0x61,0xb7,0x2e,0x27,0x28,0xe1,0x87,0x83,0x86,0xf2,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xb7,0xb1,0xb3,0xe3, + 0x93,0x80,0x82,0xac,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x73,0x63,0x64,0xb6, + 0x2e,0x28,0x28,0xe2,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0xb6,0xb0,0xb2,0xe5,0xa0,0x92,0x94,0xbe,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8b,0x78,0x7a,0xa6,0x2e,0x27,0x28,0xe1,0x4d,0x48,0x48,0xe7,0x57,0x53,0x54,0xe9,0x57,0x53,0x54,0xe9,0x57,0x53,0x54,0xe9, + 0x57,0x53,0x54,0xe9,0x81,0x76,0x78,0xcf,0x99,0x88,0x8a,0xb5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x83,0x80,0x80,0xf1,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x54,0x54,0x54,0xff,0x4d,0x4d,0x4d,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x53,0x48,0x48,0xca,0x3b,0x35,0x36,0xe4, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xae,0xa9,0xab,0xe9,0xa0,0x91,0x94,0xbe,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x73,0x63,0x64,0xb6,0x2e,0x28,0x28,0xe2,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xb6,0xb0,0xb2,0xe5,0xa0,0x92,0x94,0xbe,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8b,0x78,0x7a,0xa6,0x2e,0x27,0x28,0xe1,0x80,0x7d,0x7f,0xf0, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xad,0xa8,0xaa,0xea,0xac,0xa1,0xa3,0xce, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x83,0x80,0x80,0xf1,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x54,0x54,0x54,0xff,0x4d,0x4d,0x4d,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8c,0x78,0x7a,0xa5,0x37,0x2f,0x30,0xdc,0x5d,0x58,0x59,0xea,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xa4,0xa1,0xa4,0xef, + 0xae,0xa4,0xa6,0xd1,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x73,0x63,0x64,0xb6, + 0x2e,0x28,0x28,0xe2,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0xb6,0xb0,0xb2,0xe5,0xa0,0x92,0x94,0xbe,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8b,0x78,0x7a,0xa6,0x2e,0x27,0x28,0xe1,0x80,0x7d,0x7f,0xf0,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0xad,0xa8,0xaa,0xea,0xac,0xa1,0xa3,0xce,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x83,0x80,0x80,0xf1,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x54,0x54,0x54,0xff,0x4d,0x4d,0x4d,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x78,0x67,0x69,0xb2,0x2e,0x27,0x28,0xe1,0x7e,0x7a,0x7d,0xf0, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x9a,0x9b,0xf4,0xb9,0xb2,0xb4,0xe1,0x8e,0x7b,0x7e,0xa8,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x73,0x63,0x64,0xb6,0x2e,0x28,0x28,0xe2,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xb6,0xb0,0xb2,0xe5,0xa0,0x92,0x94,0xbe,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8b,0x78,0x7a,0xa6,0x2e,0x27,0x28,0xe1,0x80,0x7d,0x7f,0xf0, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xad,0xa8,0xaa,0xea,0xac,0xa1,0xa3,0xce, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x83,0x81,0x81,0xf2,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x54,0x54,0x54,0xff,0x4d,0x4d,0x4d,0xff, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x5b,0x4e,0x4f,0xc4,0x33,0x2d,0x2e,0xe2,0x98,0x96,0x98,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0xb0,0xab,0xad,0xe7,0x9b,0x8c,0x8e,0xb9,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x73,0x63,0x64,0xb6, + 0x2e,0x28,0x28,0xe2,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0xb6,0xb0,0xb2,0xe5,0xa0,0x92,0x94,0xbe,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8b,0x78,0x7a,0xa6,0x2e,0x27,0x28,0xe1,0x80,0x7d,0x7f,0xf0,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0xad,0xa8,0xaa,0xea,0xac,0xa1,0xa3,0xce,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x83,0x81,0x81,0xf2,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x54,0x54,0x54,0xff,0x4c,0x4c,0x4c,0xfe,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff, + 0x82,0x82,0x82,0xff,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x3e,0x35,0x36,0xd7,0x52,0x4e,0x4f,0xe8,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xa7,0xa3,0xa6,0xee,0xaa,0x9f,0xa0,0xcc,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x73,0x63,0x64,0xb6,0x2e,0x28,0x28,0xe2,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xb6,0xb0,0xb2,0xe5,0xa0,0x92,0x94,0xbe,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8b,0x78,0x7a,0xa6,0x2e,0x27,0x28,0xe1,0x80,0x7d,0x7f,0xf0, + 0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0x9b,0x98,0x9b,0xf5,0xad,0xa8,0xaa,0xea,0xac,0xa1,0xa3,0xce, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x83,0x81,0x81,0xf2,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x54,0x54,0x54,0xff,0x4c,0x4c,0x4c,0xfe, + 0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x82,0x82,0x82,0xff,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5, + 0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,0xa5,0x8d,0x79,0x7a,... [truncated message content] |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:21:52
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit f046cd839d8e29ed841ee956b68540d3ac9ba6be Author: Izik Eidus <ie...@re...> Date: Mon Nov 9 22:27:13 2009 +0200 spice: client: gl: fix glx support. Just move around touch_context and untouch_context to be at the right places. Signed-off-by: Izik Eidus <ie...@re...> diff --git a/client/display_channel.cpp b/client/display_channel.cpp index 98b9f42..ed8f2c9 100644 --- a/client/display_channel.cpp +++ b/client/display_channel.cpp @@ -693,6 +693,8 @@ DisplayChannel::~DisplayChannel() if (screen()) { screen()->set_update_interrupt_trigger(NULL); } + + destroy_canvas(); destroy_strams(); } @@ -776,6 +778,7 @@ void DisplayChannel::recreate_ogl_context_interrupt() { Canvas* canvas = _canvas.release(); if (canvas) { + ((GCanvas *)(canvas))->touch_context(); ((GCanvas *)canvas)->textures_lost(); delete canvas; } @@ -783,6 +786,8 @@ void DisplayChannel::recreate_ogl_context_interrupt() if (!create_ogl_canvas(_x_res, _y_res, _depth, 0, _rendertype)) { THROW("create_ogl_canvas failed"); } + + ((GCanvas *)(_canvas.get()))->touch_context(); } void DisplayChannel::recreate_ogl_context() @@ -917,10 +922,10 @@ bool DisplayChannel::create_ogl_canvas(int width, int height, int depth, return false; } - screen()->untouch_context(); - canvas->set_mode(width, height, depth, win, rendertype); + screen()->untouch_context(); + _canvas.reset(canvas.release()); _rendertype = rendertype; LOG_INFO("display %d: using ogl", get_id()); @@ -954,6 +959,11 @@ void DisplayChannel::destroy_canvas() Canvas* canvas = _canvas.release(); if (canvas) { +#ifdef USE_OGL + if (canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + ((GCanvas *)(canvas))->touch_context(); + } +#endif delete canvas; } } @@ -1019,6 +1029,7 @@ void DisplayChannel::handle_mode(RedPeer::InMessage* message) if (_canvas.get()) { if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) { screen()->unset_type_gl(); + screen()->untouch_context(); //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } } @@ -1038,6 +1049,7 @@ void DisplayChannel::handle_mode(RedPeer::InMessage* message) #ifdef USE_OGL if (_canvas->get_pixmap_type() == CANVAS_TYPE_GL) { + ((GCanvas *)(_canvas.get()))->touch_context(); screen()->set_update_interrupt_trigger(&_interrupt_update); screen()->set_type_gl(); } |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:21:36
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit 95a9bcb9175f2515a43212b2e5d5fe4b1534199a Author: Izik Eidus <ie...@re...> Date: Mon Nov 9 22:23:14 2009 +0200 client: fix colormap handling. Signed-off-by: Izik Eidus <ie...@re...> diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp index f4963b5..8288f55 100644 --- a/client/x11/platform.cpp +++ b/client/x11/platform.cpp @@ -2073,9 +2073,7 @@ void Platform::init() fb_config = new GLXFBConfig *[ScreenCount(x_display)]; memset(fb_config, 0, sizeof(GLXFBConfig *) * ScreenCount(x_display)); - // working with KDE and visual from glXGetVisualFromFBConfig is not working - // well. for now disabling OGL. - if (0 && threads_enable && glXQueryExtension(x_display, &err, &ev)) { + if (threads_enable && glXQueryExtension(x_display, &err, &ev)) { int num_configs; int attrlist[] = { GLX_RENDER_TYPE, GLX_RGBA_BIT, diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp index 9cce15f..5601232 100644 --- a/client/x11/red_window.cpp +++ b/client/x11/red_window.cpp @@ -954,6 +954,7 @@ void RedWindow_p::destroy(PixelsSource_p& pix_source) _glcont_copy = NULL; } XDestroyWindow(x_display, window); + XFreeColormap(x_display, _colormap); XFreeGC(x_display, pix_source.x_drawable.gc); pix_source.x_drawable.gc = NULL; pix_source.x_drawable.drawable = None; @@ -979,17 +980,14 @@ void RedWindow_p::create(RedWindow& red_window, PixelsSource_p& pix_source, int ButtonReleaseMask | PointerMotionMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask; - Colormap colormap; - - colormap = XCreateColormap(x_display, root_window, XPlatform::get_vinfo()[in_screen]->visual, + _colormap = XCreateColormap(x_display, root_window, XPlatform::get_vinfo()[in_screen]->visual, AllocNone); - win_attributes.colormap = colormap; + win_attributes.colormap = _colormap; mask |= CWColormap; window = XCreateWindow(x_display, root_window, x, y, width, height, 0, XPlatform::get_vinfo()[in_screen]->depth, InputOutput, XPlatform::get_vinfo()[in_screen]->visual, mask, &win_attributes); - XFreeColormap(x_display, colormap); if (!window) { THROW("create X window failed"); diff --git a/client/x11/red_window_p.h b/client/x11/red_window_p.h index 02cbdf9..a9ae795 100644 --- a/client/x11/red_window_p.h +++ b/client/x11/red_window_p.h @@ -61,6 +61,7 @@ protected: Icon* _icon; bool _ignore_foucs; bool _shadow_foucs_state; + Colormap _colormap; }; #endif |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:21:14
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit eb85aae81ffe544273b724cc1288ecd143ef07a6 Author: Yonit Halperin <yha...@re...> Date: Mon Nov 9 19:19:00 2009 +0200 spice client: calling the timers during modal loop in Windows diff --git a/client/process_loop.cpp b/client/process_loop.cpp index 66f676f..794f29d 100644 --- a/client/process_loop.cpp +++ b/client/process_loop.cpp @@ -394,3 +394,13 @@ void ProcessLoop::deactivate_interval_timer(Timer* timer) { _timers_queue.deactivate_interval_timer(timer); } + +int ProcessLoop::get_soonest_timeout() +{ + return _timers_queue.get_soonest_timeout(); +} + +void ProcessLoop::timers_action() +{ + _timers_queue.timers_action(); +} diff --git a/client/process_loop.h b/client/process_loop.h index df8650d..ea9eea4 100644 --- a/client/process_loop.h +++ b/client/process_loop.h @@ -205,6 +205,11 @@ public: void deactivate_interval_timer(Timer* timer); void process_events_queue(); + /* can be used for handling timers in modal loop state in Windows (mainly, + for updating the screen) */ + int get_soonest_timeout(); + void timers_action(); + void* get_owner() { return _owner;} bool is_same_thread(pthread_t thread) { return _started && pthread_equal(_thread, thread);} diff --git a/client/windows/platform.cpp b/client/windows/platform.cpp index 0fe7b24..24c9ca9 100644 --- a/client/windows/platform.cpp +++ b/client/windows/platform.cpp @@ -43,6 +43,11 @@ static Platform::EventListener* event_listener = &default_event_listener; static HWND paltform_win; static ProcessLoop* main_loop = NULL; +static const unsigned long MODAL_LOOP_TIMER_ID = 1; +static const int MODAL_LOOP_DEFAULT_TIMEOUT = 100; +static bool modal_loop_active = false; +static bool set_modal_loop_timer(); + void Platform::send_quit_request() { ASSERT(main_loop); @@ -52,6 +57,15 @@ void Platform::send_quit_request() static LRESULT CALLBACK PlatformWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { + case WM_TIMER: + if (modal_loop_active) { + main_loop->timers_action(); + if (!set_modal_loop_timer()) { + LOG_WARN("failed to set modal loop timer"); + } + } else { + LOG_WARN("received WM_TIMER not inside a modal loop"); + } case WM_ACTIVATEAPP: if (wParam) { event_listener->on_app_activated(); @@ -618,3 +632,41 @@ Icon* Platform::load_icon(int id) } return new WinIcon(icon); } + +void WinPlatform::enter_modal_loop() +{ + if (modal_loop_active) { + LOG_INFO("modal loop already active"); + return; + } + + if (set_modal_loop_timer()) { + modal_loop_active = true; + } else { + LOG_WARN("failed to create modal loop timer"); + } +} + +static bool set_modal_loop_timer() +{ + int timeout = main_loop->get_soonest_timeout(); + if (timeout == INFINITE) { + timeout = MODAL_LOOP_DEFAULT_TIMEOUT; /* for cases timeouts are added after + the enterance to the loop*/ + } + + if (!SetTimer(paltform_win, MODAL_LOOP_TIMER_ID, timeout, NULL)) { + return false; + } + return true; +} + +void WinPlatform::exit_modal_loop() +{ + if (!modal_loop_active) { + LOG_INFO("not inside the loop"); + return; + } + KillTimer(paltform_win, MODAL_LOOP_TIMER_ID); + modal_loop_active = false; +} diff --git a/client/windows/red_window.cpp b/client/windows/red_window.cpp index 0b25a79..01d82e5 100644 --- a/client/windows/red_window.cpp +++ b/client/windows/red_window.cpp @@ -191,10 +191,12 @@ LRESULT CALLBACK RedWindow_p::WindowProc(HWND hWnd, UINT message, WPARAM wParam, case WM_ENTERSIZEMOVE: case WM_ENTERMENULOOP: window->get_listener().enter_modal_loop(); + WinPlatform::enter_modal_loop(); return DefWindowProc(hWnd, message, wParam, lParam); case WM_EXITSIZEMOVE: case WM_EXITMENULOOP: window->get_listener().exit_modal_loop(); + WinPlatform::exit_modal_loop(); return DefWindowProc(hWnd, message, wParam, lParam); case WM_SETCURSOR: if (!window->_pointer_in_window) { diff --git a/client/windows/win_platform.h b/client/windows/win_platform.h index a821f63..86bbf93 100644 --- a/client/windows/win_platform.h +++ b/client/windows/win_platform.h @@ -20,6 +20,12 @@ #include "icon.h" +class WinPlatform { +public: + static void enter_modal_loop(); + static void exit_modal_loop(); +}; + class WinIcon: public Icon { public: WinIcon(HICON icon) : _icon (icon) {} |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:20:08
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit 74db5629bde5cf33f613a17cc3cdb3e2ba49233d Author: Yonit Halperin <yha...@re...> Date: Mon Nov 9 19:05:50 2009 +0200 spice client: fixed missing AutoRef diff --git a/client/red_client.cpp b/client/red_client.cpp index 969644c..cf4562b 100644 --- a/client/red_client.cpp +++ b/client/red_client.cpp @@ -328,7 +328,8 @@ void RedClient::on_connecting() void RedClient::on_connect() { - push_event(new ConnectedEvent()); + AutoRef<ConnectedEvent> event(new ConnectedEvent()); + push_event(*event); _migrate.add_channel(new MigChannel(RED_CHANNEL_MAIN, 0, get_common_caps(), get_caps())); } |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:19:44
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit 9b12f7ca8c4aa2c9b4d63f8ebd228992380c3976 Author: Yonit Halperin <yha...@re...> Date: Mon Nov 9 18:05:40 2009 +0200 spice client: remove timer interface from platform - use Application (via ProcessLoop interface). diff --git a/client/display_channel.cpp b/client/display_channel.cpp index 22da994..98b9f42 100644 --- a/client/display_channel.cpp +++ b/client/display_channel.cpp @@ -594,6 +594,33 @@ InterruptUpdate::InterruptUpdate(DisplayChannel& channel) { } +StreamsTimer::StreamsTimer(DisplayChannel& channel) + : _channel (channel) +{ +} + +void StreamsTimer::response(AbstractProcessLoop &events_loop) +{ + _channel.streams_time(); +} + +#define RESET_TIMEOUT (1000 * 5) + +class ResetTimer: public Timer { +public: + ResetTimer(RedScreen* screen, RedClient& client) : _screen(screen), _client(client) {} + virtual void response(AbstractProcessLoop &events_loop); +private: + RedScreen* _screen; + RedClient& _client; +}; + +void ResetTimer::response(AbstractProcessLoop &events_loop) +{ + _screen->unref(); + _client.deactivate_interval_timer(this); +} + class DisplayHandler: public MessageHandlerImp<DisplayChannel, RED_DISPLAY_MESSAGES_END> { public: DisplayHandler(DisplayChannel& channel) @@ -610,7 +637,7 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id, , _glz_window (glz_window) , _mark (false) , _update_mark (0) - , _streams_timer (INVALID_TIMER) + , _streams_timer (new StreamsTimer(*this)) , _next_timer_time (0) , _active_streams (NULL) , _streams_trigger (*this) @@ -817,49 +844,6 @@ void DisplayChannel::copy_pixels(const QRegion& dest_region, _canvas->copy_pixels(dest_region, dest_dc); } -class CreateTimerEvent: public SyncEvent { -public: - CreateTimerEvent(timer_proc_t proc, void* user_data) - : SyncEvent() - , _proc (proc) - , _user_data (user_data) - , _timer (INVALID_TIMER) - { - } - - virtual ~CreateTimerEvent() - { - ASSERT(_timer == INVALID_TIMER); - } - - virtual void do_response(AbstractProcessLoop& events_loop) - { - if ((_timer = Platform::create_interval_timer(_proc, _user_data)) == INVALID_TIMER) { - THROW("create timer failed"); - } - } - - TimerID release() { TimerID ret = _timer; _timer = INVALID_TIMER; return ret;} - -private: - timer_proc_t _proc; - void* _user_data; - TimerID _timer; -}; - -class DestroyTimerEvent: public Event { -public: - DestroyTimerEvent(TimerID timer) : _timer (timer) {} - - virtual void response(AbstractProcessLoop& events_loop) - { - Platform::destroy_interval_timer(_timer); - } - -private: - TimerID _timer; -}; - class ActivateTimerEvent: public Event { public: ActivateTimerEvent(DisplayChannel& channel) @@ -876,19 +860,6 @@ private: DisplayChannel& _channel; }; -void DisplayChannel::streams_timer_callback(void* opaque, TimerID timer) -{ - ((DisplayChannel *)opaque)->streams_time(); -} - -#define RESET_TIMEOUT (1000 * 5) - -void DisplayChannel::reset_timer_callback(void* opaque, TimerID timer) -{ - ((RedScreen *)opaque)->unref(); - Platform::destroy_interval_timer(timer); -} - void DisplayChannel::on_connect() { Message* message = new Message(REDC_DISPLAY_INIT, sizeof(RedcDisplayInit)); @@ -898,13 +869,6 @@ void DisplayChannel::on_connect() init->glz_dictionary_id = 1; init->glz_dictionary_window_size = get_client().get_glz_window_size(); post_message(message); - AutoRef<CreateTimerEvent> event(new CreateTimerEvent(streams_timer_callback, this)); - get_client().push_event(*event); - (*event)->wait(); - _streams_timer = (*event)->release(); - if (!(*event)->success()) { - THROW("create timer failed"); - } } void DisplayChannel::on_disconnect() @@ -917,8 +881,7 @@ void DisplayChannel::on_disconnect() screen()->set_update_interrupt_trigger(NULL); } detach_from_screen(get_client().get_application()); - AutoRef<DestroyTimerEvent> event(new DestroyTimerEvent(_streams_timer)); - get_client().push_event(*event); + get_client().deactivate_interval_timer(*_streams_timer); AutoRef<SyncEvent> sync_event(new SyncEvent()); get_client().push_event(*sync_event); (*sync_event)->wait(); @@ -1096,21 +1059,16 @@ void DisplayChannel::handle_mark(RedPeer::InMessage *message) void DisplayChannel::handle_reset(RedPeer::InMessage *message) { - TimerID reset_timer; - screen()->set_update_interrupt_trigger(NULL); if (_canvas.get()) { _canvas->clear(); } - reset_timer = Platform::create_interval_timer(reset_timer_callback, screen()->ref()); - if (reset_timer == INVALID_TIMER) { - THROW("invalid reset timer"); - } + AutoRef<ResetTimer> reset_timer(new ResetTimer(screen()->ref(), get_client())); detach_from_screen(get_client().get_application()); _palette_cache.clear(); - Platform::activate_interval_timer(reset_timer, RESET_TIMEOUT); + get_client().activate_interval_timer(*reset_timer, RESET_TIMEOUT); } void DisplayChannel::handle_inval_list(RedPeer::InMessage* message) @@ -1391,10 +1349,10 @@ void DisplayChannel::streams_time() mm_time = get_client().get_mm_time(); next_time = mm_time + 15; if (next_time && (!_next_timer_time || int(next_time - _next_timer_time) < 0)) { - Platform::activate_interval_timer(_streams_timer, MAX(int(next_time - mm_time), 0)); + get_client().activate_interval_timer(*_streams_timer, MAX(int(next_time - mm_time), 0)); _next_timer_time = next_time; } else if (!_next_timer_time) { - Platform::deactivate_interval_timer(_streams_timer); + get_client().deactivate_interval_timer(*_streams_timer); } timer_lock.unlock(); lock.unlock(); @@ -1417,7 +1375,7 @@ void DisplayChannel::activate_streams_timer() return; } delta = _next_timer_time - get_client().get_mm_time(); - Platform::activate_interval_timer(_streams_timer, delta); + get_client().activate_interval_timer(*_streams_timer, delta); } } diff --git a/client/display_channel.h b/client/display_channel.h index 59dc6a6..8600bfb 100644 --- a/client/display_channel.h +++ b/client/display_channel.h @@ -70,6 +70,13 @@ private: DisplayChannel& _channel; }; +class StreamsTimer: public Timer { +public: + StreamsTimer(DisplayChannel& channel); + virtual void response(AbstractProcessLoop& events_loop); +private: + DisplayChannel& _channel; +}; class DisplayChannel: public RedChannel, public ScreenLayer { public: @@ -145,9 +152,6 @@ private: static void set_clip_rects(const Clip& clip, uint32_t& num_clip_rects, Rect*& clip_rects, unsigned long addr_offset, uint8_t *min, uint8_t *max); - static void streams_timer_callback(void* opaque, TimerID timer); - static void reset_timer_callback(void* opaque, TimerID timer); - private: std::auto_ptr<Canvas> _canvas; PixmapCache& _pixmap_cache; @@ -168,7 +172,7 @@ private: Mutex _streams_lock; Mutex _timer_lock; - TimerID _streams_timer; + AutoRef<StreamsTimer> _streams_timer; uint32_t _next_timer_time; std::vector<VideoStream*> _streams; @@ -183,7 +187,7 @@ private: friend class VideoStream; friend class StreamsTrigger; friend class GLInterupt; - friend void streams_timer_callback(void* opaque, TimerID timer); + friend class StreamsTimer; }; #endif diff --git a/client/platform.h b/client/platform.h index fec3244..5dca717 100644 --- a/client/platform.h +++ b/client/platform.h @@ -30,13 +30,6 @@ class Icon; class Monitor; typedef std::list<Monitor*> MonitorsList; -/* TODO: tmp till each channel will handle its own thread - timers or directly through the main thread */ -#define INVALID_TIMER (~TimerID(0)) -typedef unsigned long TimerID; -typedef void (*timer_proc_t)(void* opaque, TimerID timer); - - class Platform { public: static void init(); @@ -98,12 +91,6 @@ public: class DisplayModeListner; static void set_display_mode_listner(DisplayModeListner* listener); - /* TODO: tmp till each channel will handle its own thread - timers or directly through the main thread */ - static TimerID create_interval_timer(timer_proc_t proc, void* opaque); - static bool activate_interval_timer(TimerID timer, unsigned int millisec); - static bool deactivate_interval_timer(TimerID timer); - static void destroy_interval_timer(TimerID timer); }; class Platform::EventListener { diff --git a/client/red_client.cpp b/client/red_client.cpp index 2e4758c..969644c 100644 --- a/client/red_client.cpp +++ b/client/red_client.cpp @@ -217,9 +217,10 @@ bool Migrate::abort() #define AGENT_TIMEOUT (1000 * 30) -void agent_timer_proc(void *opaque, TimerID timer) +void AgentTimer::response(AbstractProcessLoop& events_loop) { - Platform::deactivate_interval_timer(timer); + Application* app = static_cast<Application*>(events_loop.get_owner()); + app->deactivate_interval_timer(this); THROW_ERR(SPICEC_ERROR_CODE_AGENT_TIMEOUT, "vdagent timeout"); } @@ -241,7 +242,7 @@ RedClient::RedClient(Application& application) , _agent_msg_data (NULL) , _agent_msg_pos (0) , _agent_tokens (0) - , _agent_timer (Platform::create_interval_timer(agent_timer_proc, NULL)) + , _agent_timer (new AgentTimer()) , _migrate (*this) , _glz_window (0, _glz_debug) { @@ -273,16 +274,13 @@ RedClient::RedClient(Application& application) message_loop->set_handler(RED_AGENT_DATA, &RedClient::handle_agent_data, 0); message_loop->set_handler(RED_AGENT_TOKEN, &RedClient::handle_agent_tokens, sizeof(RedAgentTokens)); - if (_agent_timer == INVALID_TIMER) { - THROW("invalid agent timer"); - } start(); } RedClient::~RedClient() { ASSERT(_channels.empty()); - Platform::destroy_interval_timer(_agent_timer); + _application.deactivate_interval_timer(*_agent_timer); delete _agent_msg; } @@ -313,6 +311,16 @@ void RedClient::push_event(Event* event) _application.push_event(event); } +void RedClient::activate_interval_timer(Timer* timer, unsigned int millisec) +{ + _application.activate_interval_timer(timer, millisec); +} + +void RedClient::deactivate_interval_timer(Timer* timer) +{ + _application.deactivate_interval_timer(timer); +} + void RedClient::on_connecting() { _notify_disconnect = true; @@ -329,7 +337,7 @@ void RedClient::on_disconnect() { _migrate.abort(); _connection_id = 0; - Platform::deactivate_interval_timer(_agent_timer); + _application.deactivate_interval_timer(*_agent_timer); _agent_mon_config_sent = false; delete[] _agent_msg_data; _agent_msg_data = NULL; @@ -632,7 +640,7 @@ void RedClient::handle_init(RedPeer::InMessage* message) post_message(msg); } if (_auto_display_res) { - Platform::activate_interval_timer(_agent_timer, AGENT_TIMEOUT); + _application.activate_interval_timer(*_agent_timer, AGENT_TIMEOUT); if (_agent_connected) { send_agent_monitors_config(); } @@ -694,7 +702,7 @@ void RedClient::on_agent_reply(VDAgentReply* reply) switch (reply->type) { case VD_AGENT_MONITORS_CONFIG: post_message(new Message(REDC_ATTACH_CHANNELS, 0)); - Platform::deactivate_interval_timer(_agent_timer); + _application.deactivate_interval_timer(*_agent_timer); break; default: THROW("unexpected vdagent reply type"); diff --git a/client/red_client.h b/client/red_client.h index e22cefd..04c800c 100644 --- a/client/red_client.h +++ b/client/red_client.h @@ -112,6 +112,10 @@ public: } }; +class AgentTimer: public Timer { + virtual void response(AbstractProcessLoop& events_loop); +}; + typedef std::map< int, RedPeer::ConnectionOptions::Type> PeerConnectionOptMap; class RedClient: public RedChannel { @@ -131,6 +135,8 @@ public: virtual bool abort(); void push_event(Event* event); + void activate_interval_timer(Timer* timer, unsigned int millisec); + void deactivate_interval_timer(Timer* timer); void set_target(const char* host, uint16_t port, uint16_t sport); const char* get_password() { return _password.c_str();} @@ -206,7 +212,7 @@ private: uint8_t* _agent_msg_data; uint32_t _agent_msg_pos; uint32_t _agent_tokens; - TimerID _agent_timer; + AutoRef<AgentTimer> _agent_timer; PeerConnectionOptMap _con_opt_map; Migrate _migrate; diff --git a/client/screen.cpp b/client/screen.cpp index b79e2a1..8b7ee28 100644 --- a/client/screen.cpp +++ b/client/screen.cpp @@ -43,11 +43,9 @@ private: int _screen; }; -void periodic_update_proc(void *opaque, TimerID timer) +void UpdateTimer::response(AbstractProcessLoop& events_loop) { - RedScreen* screen = (RedScreen*)opaque; - - screen->periodic_update(); + _screen->periodic_update(); } RedScreen::RedScreen(Application& owner, int id, const std::wstring& name, int width, int height) @@ -65,7 +63,7 @@ RedScreen::RedScreen(Application& owner, int id, const std::wstring& name, int w , _key_interception (false) , _update_by_timer (true) , _forec_update_timer (0) - , _update_timer (INVALID_TIMER) + , _update_timer (new UpdateTimer(this)) , _composit_area (NULL) , _update_mark (1) , _monitor (NULL) @@ -84,10 +82,6 @@ RedScreen::RedScreen(Application& owner, int id, const std::wstring& name, int w create_composit_area(); _window.resize(_size.x, _size.y); save_position(); - _update_timer = Platform::create_interval_timer(periodic_update_proc, this); - if (_update_timer == INVALID_TIMER) { - THROW("create timer failed"); - } if ((_default_cursor = Platform::create_default_cursor()) == NULL) { THROW("create default cursor failed"); } @@ -106,7 +100,7 @@ RedScreen::~RedScreen() bool captured = is_captured(); relase_inputs(); destroy_composit_area(); - Platform::destroy_interval_timer(_update_timer); + _owner.deactivate_interval_timer(*_update_timer); _owner.on_screen_destroyed(_id, captured); region_destroy(&_dirty_region); if (_default_cursor) { @@ -333,7 +327,7 @@ void RedScreen::periodic_update() need_update = true; } else { if (!_forec_update_timer) { - Platform::deactivate_interval_timer(_update_timer); + _owner.deactivate_interval_timer(*_update_timer); _periodic_update = false; } need_update = false; @@ -357,9 +351,7 @@ void RedScreen::activate_timer() } _periodic_update = true; lock.unlock(); - if (!Platform::activate_interval_timer(_update_timer, 1000 / 30)) { - LOG_WARN("failed"); - } + _owner.activate_interval_timer(*_update_timer, 1000 / 30); } void RedScreen::update() diff --git a/client/screen.h b/client/screen.h index 3e2ffdb..957cece 100644 --- a/client/screen.h +++ b/client/screen.h @@ -27,10 +27,12 @@ #include "platform.h" #include "process_loop.h" #include "threads.h" +#include "utils.h" class Application; class ScreenLayer; class Monitor; +class RedScreen; enum { SCREEN_LAYER_DISPLAY, @@ -38,6 +40,14 @@ enum { SCREEN_LAYER_GUI, }; +class UpdateTimer: public Timer { +public: + UpdateTimer(RedScreen* screen) : _screen (screen) {} + virtual void response(AbstractProcessLoop& events_loop); +private: + RedScreen* _screen; +}; + class RedScreen: public RedWindow::Listener { public: RedScreen(Application& owner, int id, const std::wstring& name, int width, int height); @@ -87,8 +97,8 @@ public: void update(); private: - friend void periodic_update_proc(void *opaque, TimerID timer); friend class UpdateEvent; + friend class UpdateTimer; virtual ~RedScreen(); void create_composit_area(); @@ -153,7 +163,7 @@ private: bool _key_interception; bool _update_by_timer; int _forec_update_timer; - TimerID _update_timer; + AutoRef<UpdateTimer> _update_timer; RedDrawable* _composit_area; uint64_t _update_mark; diff --git a/client/windows/platform.cpp b/client/windows/platform.cpp index d93283e..0fe7b24 100644 --- a/client/windows/platform.cpp +++ b/client/windows/platform.cpp @@ -618,38 +618,3 @@ Icon* Platform::load_icon(int id) } return new WinIcon(icon); } - -class PlatformTimer: public Timer { -public: - PlatformTimer(timer_proc_t proc, void* opaque) : _proc (proc), _opaque (opaque) {} - void response(AbstractProcessLoop& events_loop) {_proc(_opaque, (TimerID)this);} - -private: - timer_proc_t _proc; - void* _opaque; -}; - -TimerID Platform::create_interval_timer(timer_proc_t proc, void* opaque) -{ - return (TimerID)(new PlatformTimer(proc, opaque)); -} - -bool Platform::activate_interval_timer(TimerID timer, unsigned int millisec) -{ - ASSERT(main_loop); - main_loop->activate_interval_timer((PlatformTimer*)timer, millisec); - return true; -} - -bool Platform::deactivate_interval_timer(TimerID timer) -{ - ASSERT(main_loop); - main_loop->deactivate_interval_timer((PlatformTimer*)timer); - return true; -} - -void Platform::destroy_interval_timer(TimerID timer) -{ - deactivate_interval_timer(timer); - ((PlatformTimer*)timer)->unref(); -} diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp index 2c9a646..f4963b5 100644 --- a/client/x11/platform.cpp +++ b/client/x11/platform.cpp @@ -2422,38 +2422,3 @@ LocalCursor* Platform::create_default_cursor() { return new XDefaultCursor(); } - -class PlatformTimer: public Timer { -public: - PlatformTimer(timer_proc_t proc, void* opaque) : _proc(proc), _opaque(opaque) {} - void response(AbstractProcessLoop& events_loop) {_proc(_opaque, (TimerID)this);} - -private: - timer_proc_t _proc; - void* _opaque; -}; - -TimerID Platform::create_interval_timer(timer_proc_t proc, void* opaque) -{ - return (TimerID)(new PlatformTimer(proc, opaque)); -} - -bool Platform::activate_interval_timer(TimerID timer, unsigned int millisec) -{ - ASSERT(main_loop); - main_loop->activate_interval_timer((PlatformTimer*)timer, millisec); - return true; -} - -bool Platform::deactivate_interval_timer(TimerID timer) -{ - ASSERT(main_loop); - main_loop->deactivate_interval_timer((PlatformTimer*)timer); - return true; -} - -void Platform::destroy_interval_timer(TimerID timer) -{ - deactivate_interval_timer(timer); - ((PlatformTimer*)timer)->unref(); -} |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:19:30
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit da98669691f5041d16d40bd6b8b794af3a822a7c Author: Izik Eidus <ie...@re...> Date: Mon Nov 9 16:07:34 2009 +0200 spice server: fix gl red_worker: put invalidate at the right places Signed-off-by: Izik Eidus <ie...@re...> diff --git a/server/red_worker.c b/server/red_worker.c index 1490f9e..af0a571 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -3989,6 +3989,8 @@ static void red_update_area(RedWorker *worker, const Rect *area) QRegion rgn; if (!(ring_item = ring_get_head(ring))) { + worker->draw_context.validate_area(worker->draw_context.canvas, &worker->dev_info.draw_area, + area); return; } @@ -4034,6 +4036,8 @@ static void red_update_area(RedWorker *worker, const Rect *area) region_destroy(&rgn); if (!last) { + worker->draw_context.validate_area(worker->draw_context.canvas, &worker->dev_info.draw_area, + area); return; } |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:19:12
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit 71567dabe364cbfd5f5a592f455c0a993f281ee0 Author: Yonit Halperin <yha...@re...> Date: Mon Nov 9 17:20:30 2009 +0200 spice client: cosmetic changes diff --git a/client/audio_channels.h b/client/audio_channels.h index 6a1c3a8..798917c 100644 --- a/client/audio_channels.h +++ b/client/audio_channels.h @@ -58,7 +58,7 @@ private: uint32_t _frame_count; }; -class RecordChannel: public RedChannel, private Platform::RecordClinet { +class RecordChannel: public RedChannel, private Platform::RecordClient { public: RecordChannel(RedClient& client, uint32_t id); ~RecordChannel(void); diff --git a/client/platform.h b/client/platform.h index ef527d3..fec3244 100644 --- a/client/platform.h +++ b/client/platform.h @@ -65,8 +65,8 @@ public: static void set_thread_priority(void *thread, ThreadPriority priority); - class RecordClinet; - static WaveRecordAbstract* create_recorder(RecordClinet& client, + class RecordClient; + static WaveRecordAbstract* create_recorder(RecordClient& client, uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels); @@ -114,10 +114,9 @@ public: virtual void on_monitors_change() = 0; }; -// TODO: tmp till all channels work with ProcessLoop -class Platform::RecordClinet { +class Platform::RecordClient { public: - virtual ~RecordClinet() {} + virtual ~RecordClient() {} virtual void add_event_source(EventSources::File& evnet_source) = 0; virtual void remove_event_source(EventSources::File& evnet_source) = 0; virtual void add_event_source(EventSources::Trigger& evnet_source) = 0; diff --git a/client/process_loop.cpp b/client/process_loop.cpp index 41aac43..66f676f 100644 --- a/client/process_loop.cpp +++ b/client/process_loop.cpp @@ -97,7 +97,7 @@ int EventsQueue::push_event(Event* event) { Lock lock(_events_lock); _events.push_back(event); - event->_generation = _events_gen; + event->set_generation(_events_gen); event->ref(); #ifdef RED_DEBUG event->set_process_loop(&_owner); @@ -116,7 +116,7 @@ void EventsQueue::process_events() return; } event = _events.front(); - if (event->_generation == _events_gen) { + if (event->get_generation() == _events_gen) { return; } _events.pop_front(); @@ -160,6 +160,22 @@ void Timer::disarm() _is_armed = false; } +#define TIMER_COMPENSATION + +void Timer::calc_next_expiration_time(uint64_t now) +{ +#ifndef TIMER_COMPENSATION + _expiratoin = now; +#endif + calc_next_expiration_time(); +#ifdef TIMER_COMPENSATION + if (_expiration <= now) { + _expiration = now; + calc_next_expiration_time(); + } +#endif +} + uint64_t Timer::get_now() { return (Platform::get_monolithic_time() / 1000 / 1000); @@ -226,7 +242,6 @@ int TimersQueue::get_soonest_timeout() return (int)(next_time - now); } -#define TIMER_COMPENSATION void TimersQueue::timers_action() { @@ -238,16 +253,7 @@ void TimersQueue::timers_action() ((*iter)->get_expiration() <= now)) { Timer* timer = *iter; _armed_timers.erase(iter); -#ifndef TIMER_COMPENSATION - timer->_experatoin = now; -#endif - timer->calc_next_expiration_time(); -#ifdef TIMER_COMPENSATION - if (timer->_expiration <= now) { - timer->_expiration = now; - timer->calc_next_expiration_time(); - } -#endif + timer->calc_next_expiration_time(now); _armed_timers.insert(timer); timer->response(_owner); } diff --git a/client/process_loop.h b/client/process_loop.h index 0b05252..df8650d 100644 --- a/client/process_loop.h +++ b/client/process_loop.h @@ -65,6 +65,10 @@ protected: #endif private: + void set_generation(uint32_t gen) { _generation = gen;} + uint32_t get_generation() { return _generation;} + +private: uint32_t _generation; friend class EventsQueue; @@ -127,6 +131,7 @@ private: void disarm(); uint64_t get_expiration() const { return _expiration;} void calc_next_expiration_time() { _expiration += _interval;} + void calc_next_expiration_time(uint64_t now); static uint64_t get_now(); diff --git a/client/red_channel.h b/client/red_channel.h index 670d652..c2f94bd 100644 --- a/client/red_channel.h +++ b/client/red_channel.h @@ -108,7 +108,6 @@ struct SyncInfo { class RedChannel: public RedChannelBase { public: - friend class RedCannel; class MessageHandler; class OutMessage; diff --git a/client/windows/platform.cpp b/client/windows/platform.cpp index b5faf75..d93283e 100644 --- a/client/windows/platform.cpp +++ b/client/windows/platform.cpp @@ -405,7 +405,7 @@ void Platform::set_process_loop(ProcessLoop& main_process_loop) main_loop = &main_process_loop; } -WaveRecordAbstract* Platform::create_recorder(RecordClinet& client, +WaveRecordAbstract* Platform::create_recorder(RecordClient& client, uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels) diff --git a/client/windows/record.cpp b/client/windows/record.cpp index bd9bc02..d962fb7 100644 --- a/client/windows/record.cpp +++ b/client/windows/record.cpp @@ -29,7 +29,7 @@ static void CALLBACK in_proc(HWAVEIN handle, UINT msg, DWORD user_data, DWORD pa recorder->trigger(); } -WaveRecorder::WaveRecorder(Platform::RecordClinet& client, uint32_t sampels_per_sec, +WaveRecorder::WaveRecorder(Platform::RecordClient& client, uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels) : _client (client) , _ring (NULL) diff --git a/client/windows/record.h b/client/windows/record.h index cd33a2a..283f282 100644 --- a/client/windows/record.h +++ b/client/windows/record.h @@ -23,7 +23,7 @@ class WaveRecorder: public WaveRecordAbstract, public EventSources::Trigger { public: - WaveRecorder(Platform::RecordClinet& client, uint32_t sampels_per_sec, + WaveRecorder(Platform::RecordClient& client, uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels); virtual ~WaveRecorder(); @@ -42,7 +42,7 @@ private: void push_frames(); private: - Platform::RecordClinet& _client; + Platform::RecordClient& _client; HWAVEIN _wave_in; uint8_t* _ring; uint32_t _ring_item_size; diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp index 8f318f2..2c9a646 100644 --- a/client/x11/platform.cpp +++ b/client/x11/platform.cpp @@ -2212,7 +2212,7 @@ void Platform::set_keyboard_modifiers(uint32_t modifiers) } } -WaveRecordAbstract* Platform::create_recorder(RecordClinet& client, +WaveRecordAbstract* Platform::create_recorder(RecordClient& client, uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels) diff --git a/client/x11/record.cpp b/client/x11/record.cpp index a220878..46abb29 100644 --- a/client/x11/record.cpp +++ b/client/x11/record.cpp @@ -42,7 +42,7 @@ void WaveRecorder::EventTrigger::on_event() _recorder.on_event(); } -WaveRecorder::WaveRecorder(Platform::RecordClinet& client, +WaveRecorder::WaveRecorder(Platform::RecordClient& client, uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels) diff --git a/client/x11/record.h b/client/x11/record.h index 540f1d2..753665f 100644 --- a/client/x11/record.h +++ b/client/x11/record.h @@ -26,7 +26,7 @@ class WaveRecorder: public WaveRecordAbstract { public: - WaveRecorder(Platform::RecordClinet& client, + WaveRecorder(Platform::RecordClient& client, uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels); @@ -44,7 +44,7 @@ private: void on_event(); private: - Platform::RecordClinet& _client; + Platform::RecordClient& _client; snd_pcm_t* _pcm; snd_pcm_hw_params_t* _hw_params; snd_pcm_sw_params_t* _sw_params; |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:18:47
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit 219105794bd42dfd36e303ca73f1a546903e1846 Author: Yonit Halperin <yha...@re...> Date: Tue Oct 20 11:18:56 2009 +0200 spice client: Transfer all channels run loop from EventsLoop class to ProcessLoop class diff --git a/client/Makefile.am b/client/Makefile.am index 357b7f7..cb80895 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -25,7 +25,6 @@ RED_COMMON_SRCS = \ debug.h \ display_channel.cpp \ display_channel.h \ - events_loop.h \ red_gl_canvas.cpp \ red_gl_canvas.h \ gl_canvas.cpp \ diff --git a/client/audio_channels.h b/client/audio_channels.h index 7615078..6a1c3a8 100644 --- a/client/audio_channels.h +++ b/client/audio_channels.h @@ -73,10 +73,10 @@ private: virtual void on_connect(); - virtual void add_evnet_sorce(EventsLoop::File& evnet_sorce); - virtual void remove_evnet_sorce(EventsLoop::File& evnet_sorce); - virtual void add_evnet_sorce(EventsLoop::Trigger& evnet_sorce); - virtual void remove_evnet_sorce(EventsLoop::Trigger& evnet_sorce); + virtual void add_event_source(EventSources::File& event_source); + virtual void remove_event_source(EventSources::File& event_source); + virtual void add_event_source(EventSources::Trigger& event_source); + virtual void remove_event_source(EventSources::Trigger& event_source); virtual void push_frame(uint8_t *frame); void send_start_mark(); diff --git a/client/cursor_channel.cpp b/client/cursor_channel.cpp index d5a64b2..fd8761a 100644 --- a/client/cursor_channel.cpp +++ b/client/cursor_channel.cpp @@ -524,7 +524,7 @@ CursorChannel::CursorChannel(RedClient& client, uint32_t id) sizeof(RedInvalOne)); handler->set_handler(RED_CURSOR_INVAL_ALL, &CursorChannel::handle_inval_all, 0); - get_events_loop().add_trigger(_cursor_trigger); + get_process_loop().add_trigger(_cursor_trigger); } CursorChannel::~CursorChannel() diff --git a/client/cursor_channel.h b/client/cursor_channel.h index 830b57f..5ac40c1 100644 --- a/client/cursor_channel.h +++ b/client/cursor_channel.h @@ -43,7 +43,7 @@ public: typedef Cache<CursorData, CursorCacheTreat, 1024> CursorCache; -class CursorModeTrigger: public EventsLoop::Trigger { +class CursorModeTrigger: public EventSources::Trigger { public: CursorModeTrigger(CursorChannel& channel); virtual void on_event(); diff --git a/client/display_channel.cpp b/client/display_channel.cpp index e9d4f19..22da994 100644 --- a/client/display_channel.cpp +++ b/client/display_channel.cpp @@ -571,7 +571,7 @@ GLInterruptRecreate::GLInterruptRecreate(DisplayChannel& channel) void GLInterruptRecreate::trigger() { Lock lock(_lock); - EventsLoop::Trigger::trigger(); + EventSources::Trigger::trigger(); _cond.wait(lock); } @@ -654,11 +654,11 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id, handler->set_handler(RED_DISPLAY_STREAM_DESTROY_ALL, &DisplayChannel::handle_stream_destroy_all, 0); - get_events_loop().add_trigger(_streams_trigger); + get_process_loop().add_trigger(_streams_trigger); #ifdef USE_OGL - get_events_loop().add_trigger(_gl_interrupt_recreate); + get_process_loop().add_trigger(_gl_interrupt_recreate); #endif - get_events_loop().add_trigger(_interrupt_update); + get_process_loop().add_trigger(_interrupt_update); } DisplayChannel::~DisplayChannel() diff --git a/client/display_channel.h b/client/display_channel.h index 894c604..59dc6a6 100644 --- a/client/display_channel.h +++ b/client/display_channel.h @@ -25,7 +25,7 @@ #include "cairo.h" #include "cache.hpp" #include "screen_layer.h" -#include "events_loop.h" +#include "process_loop.h" #ifdef USE_OGL #include "red_pixmap_gl.h" #endif @@ -36,7 +36,7 @@ class ChannelFactory; class VideoStream; class DisplayChannel; -class StreamsTrigger: public EventsLoop::Trigger { +class StreamsTrigger: public EventSources::Trigger { public: StreamsTrigger(DisplayChannel& channel); @@ -47,7 +47,7 @@ private: }; #ifdef USE_OGL -class GLInterruptRecreate: public EventsLoop::Trigger { +class GLInterruptRecreate: public EventSources::Trigger { public: GLInterruptRecreate(DisplayChannel& channel); virtual void trigger(); @@ -60,7 +60,7 @@ private: }; #endif -class InterruptUpdate: public EventsLoop::Trigger { +class InterruptUpdate: public EventSources::Trigger { public: InterruptUpdate(DisplayChannel& channel); diff --git a/client/events_loop.h b/client/events_loop.h deleted file mode 100644 index ac26a0e..0000000 --- a/client/events_loop.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _H_EVENTS_LOOP -#define _H_EVENTS_LOOP - -#include "common.h" -#include "events_loop_p.h" - -class EventSourceOld; - -class EventsLoop: public EventsLoop_p { -public: - class Trigger; - class Socket; - class File; - - EventsLoop(); - virtual ~EventsLoop(); - - void add_trigger(Trigger& trigger); - void remove_trigger(Trigger& trigger); - void add_socket(Socket& socket); - void remove_socket(Socket& socket); - void add_file(File& file); - void remove_file(File& file); - void run(); - // FIXME: temporary - need to adjust the loop for the main thread - void run_once(int timeout_milli = INFINITE); -}; - -class EventSourceOld { -public: - virtual ~EventSourceOld() {} - virtual void on_event() = 0; - -private: - virtual void action() {on_event();} - - friend class EventsLoop; -}; - -class EventsLoop::Trigger: public EventSourceOld, private EventsLoop_p::Trigger_p { -public: - Trigger(); - virtual ~Trigger(); - virtual void trigger(); - virtual void reset(); - -private: - virtual void action(); - - friend class EventsLoop; -}; - -class EventsLoop::Socket: public EventSourceOld { -protected: - virtual int get_socket() = 0; - - friend class EventsLoop; -}; - - -class EventsLoop::File: public EventSourceOld { -protected: - virtual int get_fd() = 0; - - friend class EventsLoop; -}; - -#endif - diff --git a/client/platform.h b/client/platform.h index a4310d9..ef527d3 100644 --- a/client/platform.h +++ b/client/platform.h @@ -21,7 +21,7 @@ #include "cursor.h" #include "process_loop.h" #include "event_sources.h" -#include "events_loop.h" +#include "process_loop.h" class WaveRecordAbstract; class WavePlaybackAbstract; @@ -118,10 +118,10 @@ public: class Platform::RecordClinet { public: virtual ~RecordClinet() {} - virtual void add_evnet_sorce(EventsLoop::File& evnet_sorce) = 0; - virtual void remove_evnet_sorce(EventsLoop::File& evnet_sorce) = 0; - virtual void add_evnet_sorce(EventsLoop::Trigger& evnet_sorce) = 0; - virtual void remove_evnet_sorce(EventsLoop::Trigger& evnet_sorce) = 0; + virtual void add_event_source(EventSources::File& evnet_source) = 0; + virtual void remove_event_source(EventSources::File& evnet_source) = 0; + virtual void add_event_source(EventSources::Trigger& evnet_source) = 0; + virtual void remove_event_source(EventSources::Trigger& evnet_source) = 0; virtual void push_frame(uint8_t *frame) = 0; }; diff --git a/client/record_channel.cpp b/client/record_channel.cpp index 5bba1db..d905ff6 100644 --- a/client/record_channel.cpp +++ b/client/record_channel.cpp @@ -209,24 +209,24 @@ void RecordChannel::release_message(RecordSamplesMessage *message) _messages.push_front(message); } -void RecordChannel::add_evnet_sorce(EventsLoop::File& evnet_sorce) +void RecordChannel::add_event_source(EventSources::File& event_source) { - get_events_loop().add_file(evnet_sorce); + get_process_loop().add_file(event_source); } -void RecordChannel::remove_evnet_sorce(EventsLoop::File& evnet_sorce) +void RecordChannel::remove_event_source(EventSources::File& event_source) { - get_events_loop().remove_file(evnet_sorce); + get_process_loop().remove_file(event_source); } -void RecordChannel::add_evnet_sorce(EventsLoop::Trigger& evnet_sorce) +void RecordChannel::add_event_source(EventSources::Trigger& event_source) { - get_events_loop().add_trigger(evnet_sorce); + get_process_loop().add_trigger(event_source); } -void RecordChannel::remove_evnet_sorce(EventsLoop::Trigger& evnet_sorce) +void RecordChannel::remove_event_source(EventSources::Trigger& event_source) { - get_events_loop().remove_trigger(evnet_sorce); + get_process_loop().remove_trigger(event_source); } #define FRAME_SIZE 256 diff --git a/client/red_channel.cpp b/client/red_channel.cpp index 4c6f1f8..0afe3ce 100644 --- a/client/red_channel.cpp +++ b/client/red_channel.cpp @@ -254,6 +254,7 @@ RedChannel::RedChannel(RedClient& client, uint8_t type, uint8_t id, , _incomming_message (NULL) , _message_ack_count (0) , _message_ack_window (0) + , _loop (this) , _send_trigger (*this) , _disconnect_stamp (0) , _disconnect_reason (RED_ERR_OK) diff --git a/client/red_channel.h b/client/red_channel.h index 0ffe051..670d652 100644 --- a/client/red_channel.h +++ b/client/red_channel.h @@ -23,7 +23,7 @@ #include "threads.h" #include "red_peer.h" #include "platform.h" -#include "events_loop.h" +#include "process_loop.h" enum { PASSIVE_STATE, @@ -85,7 +85,7 @@ private: ChannelCaps _remote_caps; }; -class SendTrigger: public EventsLoop::Trigger { +class SendTrigger: public EventSources::Trigger { public: SendTrigger(RedChannel& channel); @@ -95,7 +95,7 @@ private: RedChannel& _channel; }; -class AbortTrigger: public EventsLoop::Trigger { +class AbortTrigger: public EventSources::Trigger { public: virtual void on_event(); }; @@ -129,7 +129,7 @@ public: protected: RedClient& get_client() { return _client;} - EventsLoop& get_events_loop() { return _loop;} + ProcessLoop& get_process_loop() { return _loop;} MessageHandler* get_message_handler() { return _message_handler.get();} virtual void on_connecting() {} virtual void on_connect() {} @@ -188,7 +188,7 @@ private: uint32_t _message_ack_count; uint32_t _message_ack_window; - EventsLoop _loop; + ProcessLoop _loop; SendTrigger _send_trigger; AbortTrigger _abort_trigger; diff --git a/client/red_peer.h b/client/red_peer.h index f1db181..f78405b 100644 --- a/client/red_peer.h +++ b/client/red_peer.h @@ -29,10 +29,10 @@ typedef int SOCKET; #include "common.h" #include "red.h" -#include "events_loop.h" +#include "process_loop.h" #include "threads.h" -class RedPeer: protected EventsLoop::Socket { +class RedPeer: protected EventSources::Socket { public: RedPeer(); virtual ~RedPeer(); diff --git a/client/screen.cpp b/client/screen.cpp index 5d138a1..b79e2a1 100644 --- a/client/screen.cpp +++ b/client/screen.cpp @@ -751,7 +751,7 @@ bool RedScreen::need_recreate_context_gl() #endif -void RedScreen::set_update_interrupt_trigger(EventsLoop::Trigger *trigger) +void RedScreen::set_update_interrupt_trigger(EventSources::Trigger *trigger) { _update_interrupt_trigger = trigger; } diff --git a/client/screen.h b/client/screen.h index 761ae24..3e2ffdb 100644 --- a/client/screen.h +++ b/client/screen.h @@ -25,7 +25,7 @@ #include "red_window.h" #include "platform.h" -#include "events_loop.h" +#include "process_loop.h" #include "threads.h" class Application; @@ -78,7 +78,7 @@ public: void untouch_context(); bool need_recreate_context_gl(); #endif - void set_update_interrupt_trigger(EventsLoop::Trigger *trigger); + void set_update_interrupt_trigger(EventSources::Trigger *trigger); bool update_by_interrupt(); void interrupt_update(); void set_type_gl(); @@ -174,7 +174,7 @@ private: }; PointerLocation _pointer_location; int _pixel_format_index; - EventsLoop::Trigger *_update_interrupt_trigger; + EventSources::Trigger *_update_interrupt_trigger; }; #endif diff --git a/client/windows/events_loop_p.cpp b/client/windows/events_loop_p.cpp deleted file mode 100644 index 7329d16..0000000 --- a/client/windows/events_loop_p.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "common.h" -#include "events_loop.h" -#include "debug.h" -#include "utils.h" - - -EventsLoop::EventsLoop() -{ -} - -EventsLoop::~EventsLoop() -{ -} - -void EventsLoop::run() -{ - for (;;) { - run_once(); - } -} - -void EventsLoop::run_once(int timeout_milli) -{ - DWORD wait_res = WaitForMultipleObjects(_handles.size(), &_handles[0], FALSE, timeout_milli); - if (wait_res == WAIT_FAILED) { - THROW("wait failed"); - } - int event_index = wait_res - WAIT_OBJECT_0; - if (event_index < 0 || event_index >= (int)_events.size()) { - THROW("invalid event id"); - } - _events[event_index]->action(); -} - -void EventsLoop::add_socket(Socket& socket) -{ - HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!event) { - THROW("create event failed"); - } - if (WSAEventSelect(socket.get_socket(), event, FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR) { - CloseHandle(event); - THROW("event select failed"); - } - int size = _events.size(); - _events.resize(size + 1); - _handles.resize(size + 1); - _events[size] = &socket; - _handles[size] = event; -} - -void EventsLoop::remove_socket(Socket& socket) -{ - int size = _events.size(); - for (int i = 0; i < size; i++) { - if (_events[i] == &socket) { - if (WSAEventSelect(socket.get_socket(), NULL, 0) == SOCKET_ERROR) { - THROW("event select failed"); - } - u_long arg = 0; - if (ioctlsocket(socket.get_socket(), FIONBIO, &arg) == SOCKET_ERROR) { - THROW("set blocking mode failed"); - } - CloseHandle(_handles[i]); - for (i++; i < size; i++) { - _events[i - 1] = _events[i]; - _handles[i - 1] = _handles[i]; - } - _events.resize(size - 1); - _handles.resize(size - 1); - return; - } - } - THROW("socket not found"); -} - -void EventsLoop::add_trigger(Trigger& trigger) -{ - int size = _events.size(); - _events.resize(size + 1); - _handles.resize(size + 1); - _events[size] = &trigger; - _handles[size] = trigger.get_handle(); -} - -void EventsLoop::remove_trigger(Trigger& trigger) -{ - int size = _events.size(); - for (int i = 0; i < size; i++) { - if (_events[i] == &trigger) { - for (i++; i < size; i++) { - _events[i - 1] = _events[i]; - _handles[i - 1] = _handles[i]; - } - _events.resize(size - 1); - _handles.resize(size - 1); - return; - } - } - THROW("trigger not found"); -} - -EventsLoop::Trigger::Trigger() -{ - if (!(event = CreateEvent(NULL, FALSE, FALSE, NULL))) { - THROW("create event failed"); - } -} - -EventsLoop::Trigger::~Trigger() -{ - CloseHandle(event); -} - -void EventsLoop::Trigger::trigger() -{ - if (!SetEvent(event)) { - THROW("set event failed"); - } -} - -void EventsLoop::Trigger::reset() -{ - if (!ResetEvent(event)) { - THROW("set event failed"); - } -} - -void EventsLoop::Trigger::action() -{ - on_event(); -} - -void EventsLoop::add_file(File& file) -{ -} - -void EventsLoop::remove_file(File& file) -{ -} - diff --git a/client/windows/events_loop_p.h b/client/windows/events_loop_p.h deleted file mode 100644 index 6bac7b9..0000000 --- a/client/windows/events_loop_p.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _H_EVENTS_LOOP_P -#define _H_EVENTS_LOOP_P - -#include "common.h" - -#include <vector> - -class EventSourceOld; - -class EventsLoop_p { -public: - class Trigger_p; -public: - std::vector<EventSourceOld*> _events; - std::vector<HANDLE> _handles; -}; - -class EventsLoop_p::Trigger_p { -public: - HANDLE get_handle() { return event;} - -public: - HANDLE event; -}; - -#endif - diff --git a/client/windows/record.cpp b/client/windows/record.cpp index 52fc478..bd9bc02 100644 --- a/client/windows/record.cpp +++ b/client/windows/record.cpp @@ -61,7 +61,7 @@ WaveRecorder::WaveRecorder(Platform::RecordClinet& client, uint32_t sampels_per_ _frame_pos = _frame; _frame_end = _frame + frame_bytes; init_ring(sampels_per_sec, frame_bytes, frame_align); - _client.add_evnet_sorce(*this); + _client.add_event_source(*this); } catch (...) { delete[] _ring; delete[] _frame; @@ -74,7 +74,7 @@ WaveRecorder::~WaveRecorder() { waveInReset(_wave_in); reclaim(); - _client.remove_evnet_sorce(*this); + _client.remove_event_source(*this); waveInClose(_wave_in); delete[] _ring; delete[] _frame; diff --git a/client/windows/record.h b/client/windows/record.h index dab69fa..cd33a2a 100644 --- a/client/windows/record.h +++ b/client/windows/record.h @@ -21,7 +21,7 @@ #include "audio_devices.h" #include "platform.h" -class WaveRecorder: public WaveRecordAbstract, public EventsLoop::Trigger { +class WaveRecorder: public WaveRecordAbstract, public EventSources::Trigger { public: WaveRecorder(Platform::RecordClinet& client, uint32_t sampels_per_sec, uint32_t bits_per_sample, uint32_t channels); diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj index b05aec4..dac0fff 100644 --- a/client/windows/redc.vcproj +++ b/client/windows/redc.vcproj @@ -225,10 +225,6 @@ > </File> <File - RelativePath=".\events_loop_p.cpp" - > - </File> - <File RelativePath="..\gdi_canvas.cpp" > </File> @@ -441,14 +437,6 @@ > </File> <File - RelativePath="..\events_loop.h" - > - </File> - <File - RelativePath=".\events_loop_p.h" - > - </File> - <File RelativePath="..\..\common\gdi_canvas.h" > </File> diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am index aaeb331..d229ca9 100644 --- a/client/x11/Makefile.am +++ b/client/x11/Makefile.am @@ -48,7 +48,6 @@ RED_COMMON_SRCS = \ $(top_srcdir)/client/debug.h \ $(top_srcdir)/client/display_channel.cpp \ $(top_srcdir)/client/display_channel.h \ - $(top_srcdir)/client/events_loop.h \ $(top_srcdir)/client/red_gl_canvas.cpp \ $(top_srcdir)/client/red_gl_canvas.h \ $(top_srcdir)/client/gl_canvas.cpp \ @@ -105,8 +104,6 @@ bin_PROGRAMS = spicec spicec_SOURCES = \ atomic_count.h \ - events_loop_p.cpp \ - events_loop_p.h \ event_sources_p.cpp \ main.cpp \ named_pipe.h \ diff --git a/client/x11/events_loop_p.cpp b/client/x11/events_loop_p.cpp deleted file mode 100644 index a1c450b..0000000 --- a/client/x11/events_loop_p.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <sys/epoll.h> -#include <sys/fcntl.h> - -#include "events_loop.h" -#include "debug.h" -#include "utils.h" - -#ifdef USING_EVENT_FD -#include <sys/eventfd.h> -#endif - -#define NUM_EPOLL_EVENTS 10 - -#ifdef USING_EVENT_FD -#define WRITE_FD _event_fd -#define EVENT_DATA_TYPE eventfd_t -#else -#define WRITE_FD _event_write_fd -#define EVENT_DATA_TYPE uint8_t -#endif - -class EventWrapper { -public: - EventWrapper(EventsLoop& owner, EventSourceOld& event) - : _owner (owner) - , _event (&event) - , _refs (1) - { - } - - EventWrapper* ref() - { - _refs++; - return this; - } - - void unref() - { - if (!--_refs) { - _owner.remove_wrapper(this); - delete this; - } - } - - EventSourceOld* get_event() - { - return _event; - } - - void invalidate() - { - _event = NULL; - } - -private: - EventsLoop& _owner; - EventSourceOld* _event; - int _refs; -}; - -EventsLoop::EventsLoop() -{ - _epoll = epoll_create(NUM_EPOLL_EVENTS); - if (_epoll == -1) { - THROW("create epool failed"); - } -} - -EventsLoop::~EventsLoop() -{ - Events::iterator iter = _events.begin(); - for (; iter != _events.end(); iter++) { - delete *iter; - } - close(_epoll); -} - -void EventsLoop::run() -{ - for (;;) { - run_once(); - } -} - -void EventsLoop::run_once(int timeout_milli) -{ - struct epoll_event events[NUM_EPOLL_EVENTS]; - - int num_events = epoll_wait(_epoll, events, NUM_EPOLL_EVENTS, timeout_milli); - if (num_events == -1) { - if (errno == EINTR) { - return; - } - THROW("wait error eventfd failed"); - } - - for (int i = 0; i < num_events; i++) { - ((EventWrapper*)events[i].data.ptr)->ref(); - } - for (int i = 0; i < num_events; i++) { - EventWrapper* wrapper; - EventSourceOld* event; - - wrapper = (EventWrapper *)events[i].data.ptr; - if ((event = wrapper->get_event())) { - event->action(); - } - wrapper->unref(); - } -} - -void EventsLoop::add_trigger(Trigger& trigger) -{ - int fd = trigger.get_fd(); - EventWrapper* wrapper = new EventWrapper(*this, trigger); - struct epoll_event event; - event.data.ptr = wrapper; - event.events = EPOLLIN; - if (epoll_ctl(_epoll, EPOLL_CTL_ADD, fd, &event) == -1) { - THROW("epoll add failed"); - } - _events.push_back(wrapper); -} - -void EventsLoop_p::remove_wrapper(EventWrapper* wrapper) -{ - Events::iterator iter = _events.begin(); - for (;; iter++) { - if (iter == _events.end()) { - THROW("wrapper not found"); - } - if ((*iter) == wrapper) { - _events.erase(iter); - return; - } - } -} - -void EventsLoop::remove_trigger(Trigger& trigger) -{ - Events::iterator iter = _events.begin(); - for (;; iter++) { - if (iter == _events.end()) { - THROW("trigger not found"); - } - if ((*iter)->get_event() == &trigger) { - (*iter)->invalidate(); - (*iter)->unref(); - break; - } - } - int fd = trigger.get_fd(); - if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) { - THROW("epoll remove failed"); - } -} - -EventsLoop::Trigger::Trigger() -{ -#ifdef USING_EVENT_FD - _event_fd = eventfd(0, 0); - if (_event_fd == -1) { - THROW("create eventfd failed"); - } -#else - int fd[2]; - if (pipe(fd) == -1) { - THROW("create pipe failed"); - } - _event_fd = fd[0]; - _event_write_fd = fd[1]; -#endif - int flags; - if ((flags = fcntl(_event_fd, F_GETFL)) == -1) { - THROW("failed to set eventfd non block: %s", strerror(errno)); - } - - if (fcntl(_event_fd, F_SETFL, flags | O_NONBLOCK) == -1) { - THROW("failed to set eventfd non block: %s", strerror(errno)); - } -} - -EventsLoop::Trigger::~Trigger() -{ - close(_event_fd); -#ifndef USING_EVENT_FD - close(_event_write_fd); -#endif -} - -void EventsLoop::Trigger::trigger() -{ - Lock lock(_lock); - if (_pending_int) { - return; - } - _pending_int = true; - static const EVENT_DATA_TYPE val = 1; - if (::write(WRITE_FD, &val, sizeof(val)) != sizeof(val)) { - THROW("write event failed"); - } -} - -bool EventsLoop_p::Trigger_p::reset_event() -{ - Lock lock(_lock); - if (!_pending_int) { - return false; - } - EVENT_DATA_TYPE val; - if (read(_event_fd, &val, sizeof(val)) != sizeof(val)) { - THROW("event read error"); - } - _pending_int = false; - return true; -} - -void EventsLoop::Trigger::reset() -{ - reset_event(); -} - -void EventsLoop::Trigger::action() -{ - if (reset_event()) { - on_event(); - } -} - -static void set_non_blocking(int fd) -{ - int flags; - if ((flags = fcntl(fd, F_GETFL)) == -1) { - THROW("failed to set socket non block: %s", strerror(errno)); - } - - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { - THROW("failed to set socket non block: %s", strerror(errno)); - } -} - -static void set_blocking(int fd) -{ - int flags; - if ((flags = fcntl(fd, F_GETFL)) == -1) { - THROW("failed to clear socket non block: %s", strerror(errno)); - } - - if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1) { - THROW("failed to clear socket non block: %s", strerror(errno)); - } -} - -static void add_to_poll(int fd, int epoll, EventWrapper* wrapper) -{ - struct epoll_event event; - event.data.ptr = wrapper; - event.events = EPOLLIN | EPOLLOUT | EPOLLET; - if (epoll_ctl(epoll, EPOLL_CTL_ADD, fd, &event) == -1) { - THROW("epoll add failed"); - } -} - -void EventsLoop::add_socket(Socket& socket) -{ - int fd = socket.get_socket(); - set_non_blocking(fd); - EventWrapper* wrapper = new EventWrapper(*this, socket); - add_to_poll(fd, _epoll, wrapper); - _events.push_back(wrapper); -} - -static bool remove_event(EventsLoop_p::Events& events, EventSourceOld& event) -{ - EventsLoop_p::Events::iterator iter = events.begin(); - for (;; iter++) { - if (iter == events.end()) { - return false; - } - if ((*iter)->get_event() == &event) { - (*iter)->invalidate(); - (*iter)->unref(); - return true; - } - } -} - -void EventsLoop::remove_socket(Socket& socket) -{ - if (!remove_event(_events, socket)) { - THROW("socket not found"); - } - int fd = socket.get_socket(); - if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) { - THROW("epoll remove failed"); - } - set_blocking(fd); -} - -void EventsLoop::add_file(File& file) -{ - int fd = file.get_fd(); - set_non_blocking(fd); - EventWrapper* wrapper = new EventWrapper(*this, file); - add_to_poll(fd, _epoll, wrapper); - _events.push_back(wrapper); -} - -void EventsLoop::remove_file(File& file) -{ - if (!remove_event(_events, file)) { - THROW("file not found"); - } - int fd = file.get_fd(); - if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) { - THROW("epoll remove failed"); - } - set_blocking(fd); -} - diff --git a/client/x11/events_loop_p.h b/client/x11/events_loop_p.h deleted file mode 100644 index d339ca4..0000000 --- a/client/x11/events_loop_p.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _H_EVENTS_LOOP_P -#define _H_EVENTS_LOOP_P - -#include "common.h" -#include "threads.h" - -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) -#define USING_EVENT_FD -#endif - -#define INFINITE -1 - -class EventWrapper; - -class EventsLoop_p { -public: - class Trigger_p; - void remove_wrapper(EventWrapper*); - -public: - int _epoll; - typedef std::list<EventWrapper*> Events; - Events _events; - - friend class EventWrapper; -}; - -class EventsLoop_p::Trigger_p { -public: - Trigger_p() : _pending_int (false) {} - int get_fd() { return _event_fd;} - bool reset_event(); - -public: - int _event_fd; -#ifndef USING_EVENT_FD - int _event_write_fd; -#endif - bool _pending_int; - Mutex _lock; -}; - -#endif - diff --git a/client/x11/record.cpp b/client/x11/record.cpp index b68e213..a220878 100644 --- a/client/x11/record.cpp +++ b/client/x11/record.cpp @@ -20,7 +20,7 @@ #include "debug.h" -class WaveRecorder::EventTrigger: public EventsLoop::File { +class WaveRecorder::EventTrigger: public EventSources::File { public: EventTrigger(WaveRecorder& recorder, int fd); virtual void on_event(); @@ -71,7 +71,7 @@ WaveRecorder::~WaveRecorder() void WaveRecorder::cleanup() { if (_event_trigger) { - _client.remove_evnet_sorce(*_event_trigger); + _client.remove_event_source(*_event_trigger); delete _event_trigger; } @@ -194,7 +194,7 @@ bool WaveRecorder::init(uint32_t sampels_per_sec, return false; } _event_trigger = new WaveRecorder::EventTrigger(*this, pfd.fd); - _client.add_evnet_sorce(*_event_trigger); + _client.add_event_source(*_event_trigger); return true; } |
From: Yaniv K. <yk...@re...> - 2010-01-03 15:17:18
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit 78f8d4b9e8fdb09055c04e82e30b6a0290795339 Author: Yonit Halperin <yha...@re...> Date: Sun Nov 8 16:34:12 2009 +0200 spice client: creating a general process loop. The process loop is responsible for: 1) waiting for events 2) timers 3) events queue for actions that should be performed in the context of the thread and are pushed from other threads. The benefits: 1) remove duplicity: till now, there was one implementaion of events loop for the channels and another one for the main thread. 2) timers can be executed on each thread and not only on the main thread. 3) events can be pushed to each thread and not only to the main thread. In this commit, only the main thread was modified to use the new process loop. diff --git a/client/Makefile.am b/client/Makefile.am index bb78ba4..357b7f7 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -48,6 +48,7 @@ RED_COMMON_SRCS = \ pixels_source.h \ platform.h \ playback_channel.cpp \ + process_loop.cpp \ quic.cpp \ read_write_mutex.h \ record_channel.cpp \ diff --git a/client/application.cpp b/client/application.cpp index be8e69c..617934c 100644 --- a/client/application.cpp +++ b/client/application.cpp @@ -49,72 +49,35 @@ mutex_t cairo_surface_user_data_mutex; #endif -SyncEvent::SyncEvent() - : _err (false) - , _ready (false) +void ConnectedEvent::response(AbstractProcessLoop& events_loop) { + static_cast<Application*>(events_loop.get_owner())->on_connected(); } -SyncEvent::~SyncEvent() +void DisconnectedEvent::response(AbstractProcessLoop& events_loop) { -} - -void SyncEvent::responce(Application& application) -{ - try { - do_responce(application); - } catch (Exception& e) { - LOG_WARN("unhandle exception: %s", e.what()); - _err = true; - } catch (...) { - _err = true; - } - Lock lock(_mutex); - _ready = true; - _condition.notify_one(); -} - -void SyncEvent::wait() -{ - //todo: process event if on main thread - Lock lock(_mutex); - while (!_ready) { - _condition.wait(lock); - } -} - -void ConnectedEvent::responce(Application& application) -{ - application.on_connected(); -} - -void DisconnectedEvent::responce(Application& application) -{ - application.show_splash(0); + Application* app = static_cast<Application*>(events_loop.get_owner()); + app->show_splash(0); #ifndef RED_DEBUG - application.quit(SPICEC_ERROR_CODE_SUCCESS); + app->do_quit(SPICEC_ERROR_CODE_SUCCESS); #endif } -void CoonnectionError::responce(Application& application) +void ConnectionErrorEvent::response(AbstractProcessLoop& events_loop) { - application.show_splash(0); + Application* app = static_cast<Application*>(events_loop.get_owner()); + app->show_splash(0); #ifndef RED_DEBUG - application.quit(_error_code); + app->do_quit(_error_code); #endif } -void ErrorEvent::responce(Application& application) -{ - application.quit(SPICEC_ERROR_CODE_ERROR); -} - -void MonitorsQuery::do_responce(Application& application) +void MonitorsQuery::do_response(AbstractProcessLoop& events_loop) { Monitor* mon; int i = 0; - while ((mon = application.find_monitor(i++))) { + while ((mon = (static_cast<Application*>(events_loop.get_owner()))->find_monitor(i++))) { MonitorInfo info; info.size = mon->get_size(); info.depth = 32; @@ -235,15 +198,14 @@ enum AppCommands { }; Application::Application() - : _client (*this) - , _enabled_channels(RED_CHANNEL_END, true) + : ProcessLoop (this) + , _client (*this) + , _enabled_channels (RED_CHANNEL_END, true) , _main_screen (NULL) - , _quitting (false) , _active (false) , _full_screen (false) , _changing_screens (false) , _exit_code (0) - , _events_gen (0) , _active_screen (NULL) , _gui_layer (new GUILayer()) , _inputs_handler (&default_inputs_handler) @@ -251,6 +213,7 @@ Application::Application() , _title (L"SPICEc:%d") { DBG(0, ""); + Platform::set_process_loop(*this); init_monitors(); init_key_table(); @@ -324,59 +287,13 @@ void Application::remove_inputs_handler(InputsHandler& handler) _inputs_handler = &default_inputs_handler; } -void Application::process_events() -{ - _events_gen++; - for (;;) { - Event* event; - Lock lock(_events_lock); - if (_events.empty()) { - return; - } - event = _events.front(); - if (event->_generation == _events_gen) { - Platform::wakeup(); - return; - } - _events.pop_front(); - lock.unlock(); - event->responce(*this); - event->unref(); - } -} - -void Application::push_event(Event* event) -{ - Lock lock(_events_lock); - bool notify = _events.empty(); - _events.push_back(event); - event->_generation = _events_gen; - event->ref(); - if (notify) { - Platform::wakeup(); - } -} - -int Application::message_loop() -{ - for (;;) { - Platform::wait_events(); - if (Platform::process_events()) { - _quitting = true; - break; - } - process_events(); - } - return _exit_code; -} - void Application::abort() { Platform::set_event_listener(NULL); Platform::set_display_mode_listner(NULL); unpress_all(); while (!_client.abort()) { - process_events(); + ProcessLoop::process_events_queue(); Platform::msleep(100); } } @@ -397,22 +314,10 @@ void Application::connect() int Application::run() { - try { - _client.connect(); - _exit_code = message_loop(); - } catch (...) { - throw; - } - return _exit_code; -} + _client.connect(); + _exit_code = ProcessLoop::run(); + return _exit_code; -void Application::quit(int exit_code) -{ - if (!_quitting) { - _quitting = true; - _exit_code = exit_code; - Platform::send_quit_request(); - } } RedScreen* Application::find_screen(int id) diff --git a/client/application.h b/client/application.h index 1a14c5e..91afb54 100644 --- a/client/application.h +++ b/client/application.h @@ -25,6 +25,7 @@ #include "platform.h" #include "menu.h" #include "hot_keys.h" +#include "process_loop.h" class RedScreen; class Application; @@ -35,73 +36,25 @@ class Monitor; class CmdLineParser; class Menu; -class Event { -public: - Event() : _refs (1) {} - - virtual void responce(Application& application) = 0; - - Event* ref() { ++_refs; return this;} - void unref() {if (--_refs == 0) delete this;} - -protected: - virtual ~Event() {} - - AtomicCount _refs; - friend class Application; - uint32_t _generation; -}; - -class SyncEvent: public Event { -public: - SyncEvent(); - - void wait(); - bool success() { return !_err;} - - virtual void do_responce(Application& application) {} - -protected: - virtual ~SyncEvent(); - -private: - virtual void responce(Application& application); - -private: - Mutex _mutex; - Condition _condition; - bool _err; - bool _ready; -}; class ConnectedEvent: public Event { public: - ConnectedEvent() : Event() {} - virtual void responce(Application& application); + virtual void response(AbstractProcessLoop& events_loop); }; class DisconnectedEvent: public Event { public: - DisconnectedEvent() : Event() {} - virtual void responce(Application& application); + virtual void response(AbstractProcessLoop& events_loop); }; -class CoonnectionError: public Event { +class ConnectionErrorEvent: public Event { public: - CoonnectionError(int error_code) : Event(), _error_code (error_code) {} - - virtual void responce(Application& application); - + ConnectionErrorEvent(int error_code) : _error_code (error_code) {} + virtual void response(AbstractProcessLoop& events_loop); private: int _error_code; }; -class ErrorEvent: public Event { -public: - ErrorEvent() : Event() {} - virtual void responce(Application& application); -}; - struct MonitorInfo { int depth; Point size; @@ -112,8 +65,7 @@ class MonitorsQuery: public SyncEvent { public: MonitorsQuery() {} - virtual void do_responce(Application& application); - + virtual void do_response(AbstractProcessLoop& events_loop); std::vector<MonitorInfo>& get_monitors() {return _monitors;} private: @@ -138,7 +90,8 @@ enum CanvasOption { #endif }; -class Application : public Platform::EventListener, +class Application : public ProcessLoop, + public Platform::EventListener, public Platform::DisplayModeListner, public CommandTarget { public: @@ -146,8 +99,7 @@ public: virtual ~Application(); int run(); - void quit(int exit_code); - void push_event(Event* event); + void set_inputs_handler(InputsHandler& handler); void remove_inputs_handler(InputsHandler& handler); RedScreen* find_screen(int id); @@ -195,8 +147,6 @@ private: bool set_enable_channels(CmdLineParser& parser, bool enable, char *val); bool set_canvas_option(CmdLineParser& parser, char *val); bool process_cmd_line(int argc, char** argv); - void process_events(); - int message_loop(); void abort(); void init_scan_code(int index); void init_korean_scan_code(int index); @@ -234,6 +184,8 @@ private: static void init_logger(); static void init_globals(); + friend class DisconnectedEvent; + friend class ConnectionErrorEvent; friend class MonitorsQuery; friend class AutoAbort; @@ -242,15 +194,11 @@ private: PeerConnectionOptMap _peer_con_opt; std::vector<bool> _enabled_channels; std::vector<RedScreen*> _screens; - std::list<Event*> _events; RedScreen* _main_screen; - Mutex _events_lock; - bool _quitting; bool _active; bool _full_screen; bool _changing_screens; int _exit_code; - uint32_t _events_gen; RedScreen* _active_screen; KeyInfo _key_table[REDKEY_NUM_KEYS]; HotKeys _hot_keys; diff --git a/client/cursor_channel.cpp b/client/cursor_channel.cpp index a78eba3..d5a64b2 100644 --- a/client/cursor_channel.cpp +++ b/client/cursor_channel.cpp @@ -331,7 +331,7 @@ public: cursor->set_opaque(native_cursor); } - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { CursorData *cursor = *_cursor; create_cursor(); @@ -345,7 +345,8 @@ public: _channel._cursor_rect.top = _y - cursor->header().hot_spot_y; _channel._cursor_rect.bottom = _channel._cursor_rect.top + cursor->header().height; - if (application.get_mouse_mode() == RED_MOUSE_MODE_CLIENT) { + 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); @@ -381,10 +382,11 @@ public: { } - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { _channel._cursor_visible = true; - if (application.get_mouse_mode() == RED_MOUSE_MODE_CLIENT) { + 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); @@ -412,10 +414,11 @@ private: class CursorHideEvent: public Event { public: CursorHideEvent(CursorChannel& channel): _channel (channel) {} - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { _channel._cursor_visible = false; - if (application.get_mouse_mode() == RED_MOUSE_MODE_CLIENT) { + 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); @@ -431,7 +434,7 @@ private: class CursorRemoveEvent: public Event { public: CursorRemoveEvent(CursorChannel& channel): _channel (channel) {} - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { _channel._cursor_visible = false; _channel.clear_area(); @@ -455,13 +458,14 @@ class CursorModeEvent: public Event { public: CursorModeEvent(CursorChannel& channel): _channel (channel) {} - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { RedScreen* screen = _channel.screen(); if (!screen) { return; } - if (application.get_mouse_mode() == RED_MOUSE_MODE_CLIENT) { + 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 { diff --git a/client/display_channel.cpp b/client/display_channel.cpp index 2e2e4f5..e9d4f19 100644 --- a/client/display_channel.cpp +++ b/client/display_channel.cpp @@ -54,11 +54,12 @@ public: { } - virtual void do_responce(Application& application) + virtual void do_response(AbstractProcessLoop& events_loop) { + Application* app = (Application*)events_loop.get_owner(); _channel.destroy_canvas(); _channel.screen()->set_mode(_width, _height, _depth); - _channel.create_canvas(application.get_canvas_types(), _width, _height, _depth); + _channel.create_canvas(app->get_canvas_types(), _width, _height, _depth); } private: @@ -75,9 +76,9 @@ public: { } - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { - application.hide_splash(_screen_id); + static_cast<Application*>(events_loop.get_owner())->hide_splash(_screen_id); } private: @@ -831,7 +832,7 @@ public: ASSERT(_timer == INVALID_TIMER); } - virtual void do_responce(Application& application) + virtual void do_response(AbstractProcessLoop& events_loop) { if ((_timer = Platform::create_interval_timer(_proc, _user_data)) == INVALID_TIMER) { THROW("create timer failed"); @@ -850,7 +851,7 @@ class DestroyTimerEvent: public Event { public: DestroyTimerEvent(TimerID timer) : _timer (timer) {} - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { Platform::destroy_interval_timer(_timer); } @@ -866,7 +867,7 @@ public: { } - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { _channel.activate_streams_timer(); } diff --git a/client/event_sources.h b/client/event_sources.h new file mode 100644 index 0000000..a7b39ae --- /dev/null +++ b/client/event_sources.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _H_EVENT_SOURCES +#define _H_EVENT_SOURCES + +#include "common.h" +#include "event_sources_p.h" + +class EventSource; + +// TODO: the class is not thread safe +class EventSources: public EventSources_p { +public: + class Trigger; + class Socket; + class File; + class Handle; + + EventSources(); + virtual ~EventSources(); + + void add_trigger(Trigger& trigger); + void remove_trigger(Trigger& trigger); + void add_socket(Socket& socket); + void remove_socket(Socket& socket); + void add_file(File& file); + void remove_file(File& file); + void add_handle(Handle& handle); + void remove_handle(Handle& handle); + + /* return true if the events loop should quit */ + bool wait_events(int timeout_ms = INFINITE); +}; + +class EventSource { +public: + virtual ~EventSource() {} + virtual void on_event() = 0; + +private: + virtual void action() {on_event();} + + friend class EventSources; +}; + +class EventSources::Trigger: public EventSource, private Trigger_p { +public: + Trigger(); + virtual ~Trigger(); + virtual void trigger(); + virtual void reset(); + +private: + virtual void action(); + + friend class EventSources; +}; + +class EventSources::Socket: public EventSource { +protected: + virtual int get_socket() = 0; + + friend class EventSources; +}; + + +class EventSources::File: public EventSource { +protected: + virtual int get_fd() = 0; + + friend class EventSources; +}; + +class EventSources::Handle: public EventSource, public Handle_p { + + friend class EventSources; +}; + +#endif + diff --git a/client/events_loop.h b/client/events_loop.h index 50a83e1..ac26a0e 100644 --- a/client/events_loop.h +++ b/client/events_loop.h @@ -21,7 +21,7 @@ #include "common.h" #include "events_loop_p.h" -class EventSource; +class EventSourceOld; class EventsLoop: public EventsLoop_p { public: @@ -43,9 +43,9 @@ public: void run_once(int timeout_milli = INFINITE); }; -class EventSource { +class EventSourceOld { public: - virtual ~EventSource() {} + virtual ~EventSourceOld() {} virtual void on_event() = 0; private: @@ -54,7 +54,7 @@ private: friend class EventsLoop; }; -class EventsLoop::Trigger: public EventSource, private Trigger_p { +class EventsLoop::Trigger: public EventSourceOld, private EventsLoop_p::Trigger_p { public: Trigger(); virtual ~Trigger(); @@ -67,7 +67,7 @@ private: friend class EventsLoop; }; -class EventsLoop::Socket: public EventSource { +class EventsLoop::Socket: public EventSourceOld { protected: virtual int get_socket() = 0; @@ -75,7 +75,7 @@ protected: }; -class EventsLoop::File: public EventSource { +class EventsLoop::File: public EventSourceOld { protected: virtual int get_fd() = 0; diff --git a/client/inputs_channel.cpp b/client/inputs_channel.cpp index 8035bfb..d686be2 100644 --- a/client/inputs_channel.cpp +++ b/client/inputs_channel.cpp @@ -28,9 +28,9 @@ class SetInputsHandlerEvent: public Event { public: SetInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {} - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { - application.set_inputs_handler(_channel); + static_cast<Application*>(events_loop.get_owner())->set_inputs_handler(_channel); } private: @@ -41,7 +41,7 @@ class KeyModifiersEvent: public Event { public: KeyModifiersEvent(InputsChannel& channel) : _channel (channel) {} - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { Lock lock(_channel._update_modifiers_lock); _channel._active_modifiers_event = false; @@ -56,9 +56,9 @@ class RemoveInputsHandlerEvent: public SyncEvent { public: RemoveInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {} - virtual void do_responce(Application& application) + virtual void do_response(AbstractProcessLoop& events_loop) { - application.remove_inputs_handler(_channel); + static_cast<Application*>(events_loop.get_owner())->remove_inputs_handler(_channel); } private: diff --git a/client/platform.h b/client/platform.h index 0982bf6..a4310d9 100644 --- a/client/platform.h +++ b/client/platform.h @@ -19,12 +19,10 @@ #define _H_PLATFORM #include "cursor.h" +#include "process_loop.h" +#include "event_sources.h" #include "events_loop.h" -#define INVALID_TIMER (~TimerID(0)) -typedef unsigned long TimerID; -typedef void (*timer_proc_t)(void* opaque, TimerID timer); - class WaveRecordAbstract; class WavePlaybackAbstract; class Icon; @@ -32,19 +30,19 @@ class Icon; class Monitor; typedef std::list<Monitor*> MonitorsList; +/* TODO: tmp till each channel will handle its own thread + timers or directly through the main thread */ +#define INVALID_TIMER (~TimerID(0)) +typedef unsigned long TimerID; +typedef void (*timer_proc_t)(void* opaque, TimerID timer); + + class Platform { public: static void init(); - static void wait_events(); - static bool process_events(); - static void wakeup(); + static void set_process_loop(ProcessLoop& main_process_loop); static void msleep(unsigned int millisec); static void yield(); - static void send_quit_request(); - static TimerID create_interval_timer(timer_proc_t proc, void* opaque); - static bool activate_interval_timer(TimerID timer, unsigned int millisec); - static bool deactivate_interval_timer(TimerID timer); - static void destroy_interval_timer(TimerID timer); static uint64_t get_monolithic_time(); static void get_temp_dir(std::string& path); @@ -52,6 +50,8 @@ public: static void destroy_monitors(); static bool is_monitors_pos_valid(); + static void send_quit_request(); + enum ThreadPriority { PRIORITY_INVALID, PRIORITY_TIME_CRITICAL, @@ -98,6 +98,12 @@ public: class DisplayModeListner; static void set_display_mode_listner(DisplayModeListner* listener); + /* TODO: tmp till each channel will handle its own thread + timers or directly through the main thread */ + static TimerID create_interval_timer(timer_proc_t proc, void* opaque); + static bool activate_interval_timer(TimerID timer, unsigned int millisec); + static bool deactivate_interval_timer(TimerID timer); + static void destroy_interval_timer(TimerID timer); }; class Platform::EventListener { @@ -108,6 +114,7 @@ public: virtual void on_monitors_change() = 0; }; +// TODO: tmp till all channels work with ProcessLoop class Platform::RecordClinet { public: virtual ~RecordClinet() {} diff --git a/client/process_loop.cpp b/client/process_loop.cpp new file mode 100644 index 0000000..41aac43 --- /dev/null +++ b/client/process_loop.cpp @@ -0,0 +1,390 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "process_loop.h" +#include "debug.h" +#include "platform.h" +#include "utils.h" + +SyncEvent::SyncEvent() + : _err (false) + , _ready (false) +{ +} + +SyncEvent::~SyncEvent() +{ +} + +void SyncEvent::response(AbstractProcessLoop& events_loop) +{ + try { + do_response(events_loop); + } catch (Exception& e) { + LOG_WARN("unhandle exception: %s", e.what()); + _err = true; + } catch (...) { + _err = true; + } + Lock lock(_mutex); + _ready = true; + _condition.notify_one(); +} + +void SyncEvent::wait() +{ +#ifdef RED_DEBUG + ASSERT(!_process_loop || !_process_loop->is_same_thread(pthread_self())); +#endif + Lock lock(_mutex); + while (!_ready) { + _condition.wait(lock); + } +} + +class ProcessLoop::QuitEvent: public Event { +public: + QuitEvent(int error_code) : _error_code(error_code) {} + virtual void response(AbstractProcessLoop& events_loop); +private: + int _error_code; +}; + +void ProcessLoop::QuitEvent::response(AbstractProcessLoop& events_loop) +{ + events_loop.do_quit(_error_code); +} + +/* EventsQueue */ + +EventsQueue::EventsQueue(AbstractProcessLoop& owner) + : _events_gen (0) + , _owner (owner) +{ +} + +EventsQueue::~EventsQueue() +{ + clear_queue(); +} + +void EventsQueue::clear_queue() +{ + Lock lock(_events_lock); + while (!_events.empty()) { + Event* event = _events.front(); + _events.pop_front(); + event->unref(); + } +} + +int EventsQueue::push_event(Event* event) +{ + Lock lock(_events_lock); + _events.push_back(event); + event->_generation = _events_gen; + event->ref(); +#ifdef RED_DEBUG + event->set_process_loop(&_owner); +#endif + return _events.size(); +} + +void EventsQueue::process_events() +{ + _events_gen++; + + for (;;) { + Event* event; + Lock lock(_events_lock); + if (_events.empty()) { + return; + } + event = _events.front(); + if (event->_generation == _events_gen) { + return; + } + _events.pop_front(); + + lock.unlock(); + event->response(_owner); +#ifdef RED_DEBUG + event->set_process_loop(NULL); +#endif + event->unref(); + } +} + +bool EventsQueue::is_empty() +{ + Lock lock(_events_lock); + return _events.empty(); +} + +/* Timers Queue */ + +Timer::Timer() + : _is_armed (false) +{ +} + +Timer::~Timer() +{ +} + +void Timer::arm(uint32_t msec) +{ + _interval = msec; + _expiration = get_now(); + calc_next_expiration_time(); + _is_armed = true; +} + +void Timer::disarm() +{ + _is_armed = false; +} + +uint64_t Timer::get_now() +{ + return (Platform::get_monolithic_time() / 1000 / 1000); +} + +TimersQueue::TimersQueue(AbstractProcessLoop& owner) + : _owner (owner) +{ +} + +TimersQueue::~TimersQueue() +{ + clear_queue(); +} + +void TimersQueue::clear_queue() +{ + RecurciveLock lock(_timers_lock); + TimersSet::iterator iter; + for (iter = _armed_timers.begin(); iter != _armed_timers.end(); iter++) { + (*iter)->disarm(); + } + _armed_timers.clear(); +} + +void TimersQueue::activate_interval_timer(Timer* timer, unsigned int millisec) +{ + RecurciveLock lock(_timers_lock); + timer->ref(); + deactivate_interval_timer(timer); + timer->arm(millisec); + _armed_timers.insert(timer); +} + +void TimersQueue::deactivate_interval_timer(Timer* timer) +{ + RecurciveLock lock(_timers_lock); + if (timer->is_armed()) { +#ifdef RED_DEBUG + int ret = +#endif + _armed_timers.erase(timer); + ASSERT(ret); + timer->disarm(); + timer->unref(); + } +} + +int TimersQueue::get_soonest_timeout() +{ + RecurciveLock lock(_timers_lock); + TimersSet::iterator iter; + iter = _armed_timers.begin(); + if (iter == _armed_timers.end()) { + return INFINITE; + } + + uint64_t now = Timer::get_now(); + uint64_t next_time = (*iter)->get_expiration(); + + if (next_time <= now) { + return 0; + } + return (int)(next_time - now); +} + +#define TIMER_COMPENSATION + +void TimersQueue::timers_action() +{ + RecurciveLock lock(_timers_lock); + uint64_t now = Timer::get_now(); + TimersSet::iterator iter; + + while (((iter = _armed_timers.begin()) != _armed_timers.end()) && + ((*iter)->get_expiration() <= now)) { + Timer* timer = *iter; + _armed_timers.erase(iter); +#ifndef TIMER_COMPENSATION + timer->_experatoin = now; +#endif + timer->calc_next_expiration_time(); +#ifdef TIMER_COMPENSATION + if (timer->_expiration <= now) { + timer->_expiration = now; + timer->calc_next_expiration_time(); + } +#endif + _armed_timers.insert(timer); + timer->response(_owner); + } +} + +ProcessLoop::ProcessLoop(void* owner) + : _events_queue (*this) + , _timers_queue (*this) + , _owner (owner) + , _quitting (false) + , _exit_code (0) + , _started (false) + +{ + _event_sources.add_trigger(_wakeup_trigger); +} + +ProcessLoop::~ProcessLoop() +{ + _event_sources.remove_trigger(_wakeup_trigger); +} + +int ProcessLoop::run() +{ + _thread = pthread_self(); + _started = true; + for (;;) { + if (_event_sources.wait_events(_timers_queue.get_soonest_timeout())) { + _quitting = true; + break; + } + _timers_queue.timers_action(); + process_events_queue(); + if (_quitting) { + break; + } + } + + return _exit_code; +} + +void ProcessLoop::do_quit(int error_code) +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + if (_quitting) { + return; + } + _quitting = true; + _exit_code = error_code; +} + +void ProcessLoop::quit(int error_code) +{ + AutoRef<QuitEvent> quit_event(new QuitEvent(error_code)); + push_event(*quit_event); +} + +void ProcessLoop::process_events_queue() +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + _events_queue.process_events(); + if (!_events_queue.is_empty()) { + wakeup(); + } +} + +void ProcessLoop::wakeup() +{ + _wakeup_trigger.trigger(); +} + +void ProcessLoop::add_trigger(EventSources::Trigger& trigger) +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + _event_sources.add_trigger(trigger); +} + +void ProcessLoop::remove_trigger(EventSources::Trigger& trigger) +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + _event_sources.remove_trigger(trigger); +} + +void ProcessLoop::add_socket(EventSources::Socket& socket) +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + _event_sources.add_socket(socket); +} + +void ProcessLoop::remove_socket(EventSources::Socket& socket) +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + _event_sources.remove_socket(socket); +} + +void ProcessLoop::add_file(EventSources::File& file) +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + _event_sources.add_file(file); +} + +void ProcessLoop::remove_file(EventSources::File& file) +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + _event_sources.remove_file(file); +} + +void ProcessLoop::add_handle(EventSources::Handle& handle) +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + _event_sources.add_handle(handle); +} + +void ProcessLoop::remove_handle(EventSources::Handle& handle) +{ + ASSERT(!_started || pthread_equal(pthread_self(), _thread)); + _event_sources.remove_handle(handle); +} + +void ProcessLoop::push_event(Event* event) +{ + int queue_size = _events_queue.push_event(event); + if (queue_size == 1) { // queue was empty before the push + wakeup(); + } +} + +void ProcessLoop::activate_interval_timer(Timer* timer, unsigned int millisec) +{ + _timers_queue.activate_interval_timer(timer, millisec); + + if (_started && !pthread_equal(pthread_self(), _thread)) { + wakeup(); + } +} + +void ProcessLoop::deactivate_interval_timer(Timer* timer) +{ + _timers_queue.deactivate_interval_timer(timer); +} diff --git a/client/process_loop.h b/client/process_loop.h new file mode 100644 index 0000000..0b05252 --- /dev/null +++ b/client/process_loop.h @@ -0,0 +1,233 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _H_PROCESS_LOOP +#define _H_PROCESS_LOOP + +#include "common.h" + +#include <set> + +#include "event_sources.h" +#include "threads.h" + +class AbstractProcessLoop { +public: + virtual ~AbstractProcessLoop() {} + virtual int run() = 0; + virtual void do_quit(int error_code) = 0; + virtual void* get_owner() = 0; + virtual bool is_same_thread(pthread_t thread) = 0; +}; + +class EventBase { +public: + EventBase() : _refs (1) {} + + virtual void response(AbstractProcessLoop& events_loop) = 0; + + EventBase* ref() { ++_refs; return this;} + void unref() {if (--_refs == 0) delete this;} + +protected: + virtual ~EventBase() {} + +private: + AtomicCount _refs; +}; + +class EventsQueue; + +class Event: public EventBase { +#ifdef RED_DEBUG +public: + Event() : _process_loop (NULL) {} + +private: + void set_process_loop(AbstractProcessLoop* process_loop) { _process_loop = process_loop;} + +protected: + AbstractProcessLoop* _process_loop; +#endif + +private: + uint32_t _generation; + + friend class EventsQueue; +}; + +class EventsQueue { +public: + EventsQueue(AbstractProcessLoop& owner); + virtual ~EventsQueue(); + /* return the size of the queue (post-push) */ + int push_event(Event* event); + void process_events(); + bool is_empty(); + +private: + void clear_queue(); + +private: + std::list<Event*> _events; + Mutex _events_lock; + uint32_t _events_gen; + + AbstractProcessLoop& _owner; +}; + +class SyncEvent: public Event { +public: + SyncEvent(); + + void wait(); + bool success() { return !_err;} + + virtual void do_response(AbstractProcessLoop& events_loop) {} + +protected: + virtual ~SyncEvent(); + +private: + virtual void response(AbstractProcessLoop& events_loop); + +private: + Mutex _mutex; + Condition _condition; + bool _err; + bool _ready; +}; + +class TimersQueue; + +class Timer: public EventBase { +public: + Timer(); + bool is_armed() {return _is_armed;} + +protected: + virtual ~Timer(); + +private: + void arm(uint32_t msec); + void disarm(); + uint64_t get_expiration() const { return _expiration;} + void calc_next_expiration_time() { _expiration += _interval;} + + static uint64_t get_now(); + +private: + bool _is_armed; + uint32_t _interval; + uint64_t _expiration; + + class Compare { + public: + bool operator () (const Timer* timer1, const Timer* timer2) const + { + if (timer1->get_expiration() < timer2->get_expiration()) { + return true; + } else if (timer1->get_expiration() > timer2->get_expiration()) { + return false; + } else { // elements must be unique (for insertion into set) + return timer1 < timer2; + } + } + }; + + friend class TimersQueue; +}; + +class TimersQueue { +public: + TimersQueue(AbstractProcessLoop& owner); + virtual ~TimersQueue(); + + void activate_interval_timer(Timer* timer, unsigned int millisec); + void deactivate_interval_timer(Timer* timer); + + int get_soonest_timeout(); + void timers_action(); + +private: + void clear_queue(); + +private: + typedef std::set<Timer*, Timer::Compare> TimersSet; + TimersSet _armed_timers; + RecurciveMutex _timers_lock; + AbstractProcessLoop& _owner; +}; + +class ProcessLoop: public AbstractProcessLoop { +public: + class QuitEvent; + ProcessLoop(void* owner); + virtual ~ProcessLoop(); + int run(); + + void quit(int error_code); + + /* Event sources to track. Note: the following methods are not thread safe, thus, + they mustn't be called from other thread than the process loop thread. */ + void add_trigger(EventSources::Trigger& trigger); + void remove_trigger(EventSources::Trigger& trigger); + void add_socket(EventSources::Socket& socket); + void remove_socket(EventSources::Socket& socket); + void add_file(EventSources::File& file); + void remove_file(EventSources::File& file); + void add_handle(EventSources::Handle& handle); + void remove_handle(EventSources::Handle& handle); + + /* events queue */ + void push_event(Event* event); + + void activate_interval_timer(Timer* timer, unsigned int millisec); + void deactivate_interval_timer(Timer* timer); + + void process_events_queue(); + void* get_owner() { return _owner;} + + bool is_same_thread(pthread_t thread) { return _started && pthread_equal(_thread, thread);} + +protected: + class WakeupTrigger: public EventSources::Trigger { + public: + virtual void on_event() {} + }; + + void wakeup(); + void do_quit(int error_code); + + friend class QuitEvent; // allowing access to quit + +private: + EventSources _event_sources; + EventsQueue _events_queue; + TimersQueue _timers_queue; + + WakeupTrigger _wakeup_trigger; + + void* _owner; + + bool _quitting; + int _exit_code; + bool _started; + pthread_t _thread; +}; + +#endif diff --git a/client/red_client.cpp b/client/red_client.cpp index 941321f..2e4758c 100644 --- a/client/red_client.cpp +++ b/client/red_client.cpp @@ -19,6 +19,7 @@ #include <math.h> #include "red_client.h" #include "application.h" +#include "process_loop.h" #include "utils.h" #include "debug.h" @@ -397,10 +398,12 @@ void RedClient::on_channel_disconnected(RedChannel& channel) _notify_disconnect = false; int connection_error = channel.get_connection_error(); if (connection_error == SPICEC_ERROR_CODE_SUCCESS) { + AutoRef<DisconnectedEvent> disconn_event(new DisconnectedEvent()); LOG_INFO("disconneted"); - push_event(new DisconnectedEvent()); + push_event(*disconn_event); } else { - push_event(new CoonnectionError(connection_error)); + AutoRef<ConnectionErrorEvent> error_event(new ConnectionErrorEvent(connection_error)); + push_event(*error_event); } } disconnect_channels(); diff --git a/client/red_client.h b/client/red_client.h index d799e78..e22cefd 100644 --- a/client/red_client.h +++ b/client/red_client.h @@ -29,9 +29,9 @@ #include "audio_channels.h" #include "red.h" #include "vd_agent.h" +#include "process_loop.h" class Application; -class Event; class MigChannel: public RedChannelBase { public: diff --git a/client/screen.cpp b/client/screen.cpp index b33560e..5d138a1 100644 --- a/client/screen.cpp +++ b/client/screen.cpp @@ -30,9 +30,10 @@ class UpdateEvent: public Event { public: UpdateEvent(int screen) : _screen (screen) {} - virtual void responce(Application& application) + virtual void response(AbstractProcessLoop& events_loop) { - RedScreen* screen = application.find_screen(_screen); + Application* app = static_cast<Application*>(events_loop.get_owner()); + RedScreen* screen = app->find_screen(_screen); if (screen) { screen->update(); } diff --git a/client/screen_layer.cpp b/client/screen_layer.cpp index f521b46..9940ad8 100644 --- a/client/screen_layer.cpp +++ b/client/screen_layer.cpp @@ -24,18 +24,23 @@ class AttacheLayerEvent: public SyncEvent { public: - AttacheLayerEvent(ScreenLayer& layer, int screen_id) : _layer (layer), _screen_id (screen_id) {} + AttacheLayerEvent(ScreenLayer& layer, int screen_id) + : _layer (layer) + , _screen_id (screen_id) + { + } - virtual void do_responce(Application& application); + virtual void do_response(AbstractProcessLoop& events_loop); private: ScreenLayer& _layer; int _screen_id; }; -void AttacheLayerEvent::do_responce(Application& application) +void AttacheLayerEvent::do_response(AbstractProcessLoop& events_loop) { - AutoRef<RedScreen> screen(application.get_screen(_screen_id)); + Application* app = (Application*)(events_loop.get_owner()); + AutoRef<RedScreen> screen(app->get_screen(_screen_id)); (*screen)->attach_layer(_layer); } @@ -43,13 +48,13 @@ class DetacheLayerEvent: public SyncEvent { public: DetacheLayerEvent(ScreenLayer& _layer) : _layer (_layer) {} - virtual void do_responce(Application& application); + virtual void do_response(AbstractProcessLoop& events_loop); private: ScreenLayer& _layer; }; -void DetacheLayerEvent::do_responce(Application& application) +void DetacheLayerEvent::do_response(AbstractProcessLoop& events_loop) { _layer.screen()->detach_layer(_layer); } diff --git a/client/windows/event_sources_p.cpp b/client/windows/event_sources_p.cpp new file mode 100644 index 0000000..4a11b77 --- /dev/null +++ b/client/windows/event_sources_p.cpp @@ -0,0 +1,209 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "common.h" +#include "event_sources.h" +#include "debug.h" +#include "utils.h" + +bool EventSources_p::process_system_events() +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + + if (msg.message == WM_QUIT) { + return true; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return false; +} + +void EventSources_p::add_event(HANDLE event, EventSource* source) +{ + int size = _events.size(); + _events.resize(size + 1); + _handles.resize(size + 1); + _events[size] = source; + _handles[size] = event; +} + +void EventSources_p::remove_event(EventSource* source) +{ + int size = _events.size(); + for (int i = 0; i < size; i++) { + if (_events[i] == source) { + for (i++; i < size; i++) { + _events[i - 1] = _events[i]; + _handles[i - 1] = _handles[i]; + } + _events.resize(size - 1); + _handles.resize(size - 1); + return; + } + } + THROW("event not found"); +} + +EventSources::EventSources() +{ +} + +EventSources::~EventSources() +{ +} + +bool EventSources::wait_events(int timeout_ms) +{ + if (_handles.empty()) { + if (WaitMessage()) { + return process_system_events(); + } else { + THROW("wait failed %d", GetLastError()); + } + } + + DWORD wait_res = MsgWaitForMultipleObjectsEx(_handles.size(), &_handles[0], timeout_ms, + QS_ALLINPUT, 0); + if (wait_res == WAIT_TIMEOUT) { + return false; + } + + if (wait_res == WAIT_FAILED) { + THROW("wait failed %d", GetLastError()); + } + + int event_index = wait_res - WAIT_OBJECT_0; + if (event_index == _handles.size()) { + return process_system_events(); + } else if ((event_index >= 0) && (event_index < (int)_handles.size())) { + _events[event_index]->action(); + return false; + } else { + THROW("invalid event id"); + } +} + +void EventSources::add_socket(Socket& socket) +{ + HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!event) { + THROW("create event failed"); + } + if (WSAEventSelect(socket.get_socket(), event, + FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR) { + CloseHandle(event); + THROW("event select failed"); + } + add_event(event, &socket); +} + +void EventSources::remove_socket(Socket& socket) +{ + int size = _events.size(); + for (int i = 0; i < size; i++) { + if (_events[i] == &socket) { + if (WSAEventSelect(socket.get_socket(), NULL, 0) == SOCKET_ERROR) { + THROW("event select failed"); + } + u_long arg = 0; + if (ioctlsocket(socket.get_socket(), FIONBIO, &arg) == SOCKET_ERROR) { + THROW("set blocking mode failed"); + } + CloseHandle(_handles[i]); + for (i++; i < size; i++) { + _events[i - 1] = _events[i]; + _handles[i - 1] = _handles[i]; + } + _events.resize(size - 1); + _handles.resize(size - 1); + return; + } + } + THROW("socket not found"); +} + +void EventSources::add_handle(Handle& handle) +{ + add_event(handle.get_handle(), &handle); +} + +void EventSources::remove_handle(Handle& handle) +{ + remove_event(&handle); +} + +Handle_p::Handle_p() +{ + if (!(_event = CreateEvent(NULL, FALSE, FALSE, NULL))) { + THROW("create event failed"); + } +} + +Handle_p::~Handle_p() +{ + CloseHandle(_event); +} + +void EventSources::add_trigger(Trigger& trigger) +{ + add_event(trigger.get_handle(), &trigger); +} + +void EventSources::remove_trigger(Trigger& trigger) +{ + remove_event(&trigger); +} + + +EventSources::Trigger::Trigger() +{ +} + +EventSources::Trigger::~Trigger() +{ +} + + +void EventSources::Trigger::trigger() +{ + if (!SetEvent(_event)) { + THROW("set event failed"); + } +} + +void EventSources::Trigger::reset() +{ + if (!ResetEvent(_event)) { + THROW("set event failed"); + } +} + +void EventSources::Trigger::action() +{ + on_event(); +} + +void EventSources::add_file(File& file) +{ +} + +void EventSources::remove_file(File& file) +{ +} + diff --git a/client/windows/event_sources_p.h b/client/windows/event_sources_p.h new file mode 100644 index 0000000..3477605 --- /dev/null +++ b/client/windows/event_sources_p.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _H_EVENT_SOURCES_P +#define _H_EVENT_SOURCES_P + +#include "common.h" + +#include <vector> + +class EventSource; +class Handle_p; + +class EventSources_p { +protected: + /* return true if quit should be performed */ + bool process_system_events(); + void add_event(HANDLE event, EventSource* source); + void remove_event(EventSource* source); +public: + std::vector<EventSource*> _events; + std::vector<HANDLE> _handles; +}; + +class Handle_p { +public: + Handle_p(); + virtual ~Handle_p(); + HANDLE get_handle() { return _event;} +protected: + HANDLE _event; +}; + +class Trigger_p: public Handle_p { +}; + +#endif + diff --git a/client/windows/events_loop_p.h b/client/windows/events_loop_p.h index 8361398..6bac7b9 100644 --- a/client/windows/events_loop_p.h +++ b/client/windows/events_loop_p.h @@ -22,15 +22,17 @@ #include <vector> -class EventSource; +class EventSourceOld; class EventsLoop_p { public: - std::vector<EventSource*> _events; + class Trigger_p; +public: + std::vector<EventSourceOld*> _events; std::vector<HANDLE> _handles; }; -class Trigger_p { +class EventsLoop_p::Trigger_p { public: HANDLE get_handle() { return event;} diff --git a/client/windows/named_pipe.cpp b/client/windows/named_pipe.cpp index f33c476..44459fa 100644 --- a/client/windows/named_pipe.cpp +++ b/client/windows/named_pipe.cpp @@ -20,23 +20,22 @@ #include "utils.h" #include "debug.h" -PipeBuffer::PipeBuffer(HANDLE pipe) +PipeBuffer::PipeBuffer(HANDLE pipe, ProcessLoop& process_loop) : _handler (NULL) , _pipe (pipe) , _start (0) , _end (0) , _pending (false) + , _process_loop(process_loop) { ZeroMemory(&_overlap, sizeof(_overlap)); - _overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - _event_handle = _overlap.hEvent; - WinPlatform::add_event(*this); + _overlap.hEvent = this->get_handle(); + _process_loop.add_handle(*this); } PipeBuffer::~PipeBuffer() { - WinPlatform::remove_event(*this); - CloseHandle(_event_handle); + _process_loop.remove_handle(*this); } DWORD PipeBuffer::get_overlapped_bytes() @@ -127,10 +126,10 @@ void PipeWriter::on_event() } } -WinConnection::WinConnection(HANDLE pipe) +WinConnection::WinConnection(HANDLE pipe, ProcessLoop& process_loop) : _pipe (pipe) - , _writer (pipe) - , _reader (pipe) + , _writer (pipe, process_loop) + , _reader (pipe, process_loop) { } @@ -158,24 +157,24 @@ void WinConnection::set_handler(NamedPipe::ConnectionInterface* handler) _writer.set_handler(handler); } -WinListener::WinListener(const char *name, NamedPipe::ListenerInterface &listener_interface) +WinListener::WinListener(const char *name, NamedPipe::ListenerInterface &listener_interface, + ProcessLoop& process_loop) : _listener_interface (listener_interface) , _pipe (0) + , _process_loop (process_loop) { _pipename = new TCHAR[PIPE_MAX_NAME_LEN]; swprintf_s(_pipename, PIPE_MAX_NAME_LEN, L"%s%S", PIPE_PREFIX, name); ZeroMemory(&_overlap, sizeof(_overlap)); - _overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - _event_handle = _overlap.hEvent; - WinPlatform::add_event(*this); + _overlap.hEvent = this->get_handle(); + _process_loop.add_handle(*this); create_pipe(); } WinListener::~WinListener() { CancelIo(_pipe); - WinPlatform::remove_event(*this); - CloseHandle(_event_handle); + _process_loop.remove_handle(*this); delete[] _pipename; } @@ -188,7 +187,7 @@ void WinListener::on_event() return; } DBG(0, "Pipe connected 0x%p", _pipe); - WinConnection *con = new WinConnection(_pipe); + WinConnection *con = new WinConnection(_pipe, _process_loop); NamedPipe::ConnectionInterface &con_interface = _listener_interface.create(); con->set_handler(&con_interface); con_interface.bind((NamedPipe::ConnectionRef)con); @@ -213,7 +212,7 @@ void WinListener::create_pipe() break; case ERROR_PIPE_CONNECTED: { DBG(0, "Pipe already connected"); - WinConnection *con = new WinConnection(_pipe); + WinConnection *con = new WinConnection(_pipe, _process_loop); NamedPipe::ConnectionInterface &con_interface = _listener_interface.create(); con->set_handler(&con_interface); con_interface.bind((NamedPipe::ConnectionRef)con); diff --git a/client/windows/named_pipe.h b/client/windows/named_pipe.h index 578c34d..fcdc0dd 100644 --- a/client/windows/named_pipe.h +++ b/client/windows/named_pipe.h @@ -19,8 +19,9 @@ #define _H_NAMED_PIPE #include <windows.h> +#include "process_loop.h" +#include "event_sources.h" #include "platform.h" -#include "win_platform.h" #define PIPE_TIMEOUT 5000 #define PIPE_BUF_SIZE 8192 @@ -29,9 +30,9 @@ class WinConnection; -class PipeBuffer: public EventOwner { +class PipeBuffer: public EventSources::Handle { public: - PipeBuffer(HANDLE pipe); + PipeBuffer(HANDLE pipe, ProcessLoop& process_loop); ~PipeBuffer(); void set_handler(NamedPipe::ConnectionInterface* handler) { _handler = handler;} DWORD get_overlapped_bytes(); @@ -44,25 +45,26 @@ protected: uint32_t _end; uint8_t _data[PIPE_BUF_SIZE]; bool _pending; + ProcessLoop& _process_loop; }; class PipeReader: public PipeBuffer { public: - PipeReader(HANDLE pipe) : PipeBuffer(pipe) {} + PipeReader(HANDLE pipe, ProcessLoop& process_loop) : PipeBuffer(pipe, process_loop) {} int32_t read(uint8_t *buf, int32_t size); void on_event(); }; class PipeWriter: public PipeBuffer { public: - PipeWriter(HANDLE pipe) : PipeBuffer(pipe) {} + PipeWriter(HANDLE pipe, ProcessLoop& process_loop) : PipeBuffer(pipe, process_loop) {} int32_t write(const uint8_t *buf, int32_t size); void on_event(); }; class WinConnection { public: - WinConnection(HANDLE pipe); + WinConnection(HANDLE pipe, ProcessLoop& process_loop); ~WinConnection(); int32_t read(uint8_t *buf, int32_t size); int32_t write(const uint8_t *buf, int32_t size); @@ -74,9 +76,10 @@ private: PipeReader _reader; }; -class WinListener: public EventOwner { +class WinListener: public EventSources::Handle { public: - WinListener(const char *name, NamedPipe::ListenerInterface &listener_interface); + WinListener(const char *name, NamedPipe::ListenerInterface &listener_interface, + ProcessLoop& process_loop); ~WinListener(); void on_event(); @@ -88,6 +91,7 @@ private: NamedPipe::ListenerInterface &_listener_interface; OVERLAPPED _overlap; HANDLE _pipe; + ProcessLoop& _process_loop; }; #endif diff --git a/client/windows/platform.cpp b/client/windows/platform.cpp index 773fa61..b5faf75 100644 --- a/client/windows/platform.cpp +++ b/client/windows/platform.cpp @@ -28,9 +28,6 @@ #include "cursor.h" #include "named_pipe.h" -#define WM_USER_WAKEUP WM_USER -#define NUM_TIMERS 100 - int gdi_handlers = 0; extern HINSTANCE instance; @@ -44,61 +41,17 @@ public: static DefaultEventListener default_event_listener; static Platform::EventListener* event_listener = &default_event_listener; static HWND paltform_win; -static HANDLE main_tread; - -struct Timer { - TimerID id; - timer_proc_t proc; - void* opaque; - Timer *next; -}; - -Timer timers[NUM_TIMERS]; -Timer* free_timers = NULL; -Mutex timers_lock; - -static void free_timer(Timer* timer) -{ - Lock lock(timers_lock); - timer->proc = NULL; - timer->next = free_timers; - free_timers = timer; -} +static ProcessLoop* main_loop = NULL; -static void init_timers() -{ - for (int i = 0; i < NUM_TIMERS; i++) { - timers[i].id = i; - free_timer(&timers[i]); - } -} - -static Timer* alloc_timer() +void Platform::send_quit_request() { - Timer* timer; - - Lock lock(timers_lock); - if (!(timer = free_timers)) { - return NULL; - } - - free_timers = free_timers->next; - return timer; + ASSERT(main_loop); + main_loop->quit(0); } static LRESULT CALLBACK PlatformWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { - case WM_TIMER: { - TimerID id = wParam - 1; - ASSERT(id < NUM_TIMERS); - Timer* timer = &timers[id]; - timer->proc(timer->opaque, id); - break; - } - case WM_USER_WAKEUP: { - break; - } case WM_ACTIVATEAPP: if (wParam) { event_listener->on_app_activated(); @@ -147,80 +100,21 @@ static void create_message_wind() paltform_win = window; } -void Platform::send_quit_request() -{ - ASSERT(GetCurrentThread() == main_tread); - PostQuitMessage(0); -} - -static std::vector<HANDLE> events; -static std::vector<EventOwner*> events_owners; - -void WinPlatform::add_event(EventOwner& event_owner) -{ - ASSERT(main_tread == GetCurrentThread()); - int size = events.size(); - if (size == MAXIMUM_WAIT_OBJECTS - 1) { - THROW("reached maximum allowed events to wait for"); - } - events.resize(size + 1); - events_owners.resize(size + 1); - events[size] = event_owner.get_event_handle(); - events_owners[size] = &event_owner; -} - -void WinPlatform::remove_event(EventOwner& event_owner) -{ - ASSERT(main_tread == GetCurrentThread()); - int size = events.size(); - for (int i = 0; i < size; i++) { - if (events_owners[i] == &event_owner) { - for (i++; i < size; i++) { - events[i - 1] = events[i]; - events_owners[i - 1] = events_owners[i]; - } - events.resize(size - 1); - events_owners.resize(size - 1); - return; - } - } - THROW("event owner not found"); -} - -void Platform::wait_events() -{ - if (!events.size()) { - if (!WaitMessage()) { - THROW("wait failed %d", GetLastError()); - } - return; - } - - DWORD r = MsgWaitForMultipleObjectsEx(events.size(), &events[0], INFINITE, QS_ALLINPUT, 0); - if (r == WAIT_OBJECT_0 + events.size()) { - return; - } - if (r >= WAIT_OBJECT_0 && r <= WAIT_OBJECT_0 + events.size() - 1) { - events_owners[r - WAIT_OBJECT_0]->on_event(); - } else if (r == WAIT_FAILED) { - THROW("wait multiple failed %d", GetLastError()); - } else { - THROW("unexpected wait return %u", r); - } -} - NamedPipe::ListenerRef NamedPipe::create(const char *name, ListenerInterface& listener_interface) { - return (ListenerRef)(new WinListener(name, listener_interface)); + ASSERT(main_loop && main_loop->is_same_thread(pthread_self())); + return (ListenerRef)(new WinListener(name, listener_interface, *main_loop)); } void NamedPipe::destroy(ListenerRef listener_ref) { + ASSERT(main_loop && main_loop->is_same_thread(pthread_self())); delete (WinListener *)listener_ref; } void NamedPipe::destroy_connection(ConnectionRef conn_ref) { + ASSERT(main_loop && main_loop->is_same_thread(pthread_self())); delete (WinConnection *)conn_ref; } @@ -234,26 +128,6 @@ int32_t NamedPipe::write(ConnectionRef conn_ref, const uint8_t *buf, int32_t siz return ((WinConnection *)conn_ref)->write(buf, size); } -void Platform::wakeup() -{ - if (!PostMessage(paltform_win, WM_USER_WAKEUP, 0, 0)) { - THROW("post failed %d", GetLastError()); - } -} - -bool Platform::process_events() -{ - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_QUIT) { - return true; - } - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return false; -} - void Platform::msleep(unsigned int msec) { Sleep(msec); @@ -302,48 +176,6 @@ void Platform::set_event_listener(EventListener* listener) event_listener = listener ? listener : &default_event_listener; } -TimerID Platform::create_interval_timer(timer_proc_t proc, void* opaque) -{ - Timer* timer = alloc_timer(); - if (!timer) { - return INVALID_TIMER; - } - timer->proc = proc; - timer->opaque = opaque; - return timer->id; -} - -bool Platform::activate_interval_timer(TimerID timer, unsigned int millisec) -{ - if (timer >= NUM_TIMERS) { - return false; - } - - if (!SetTimer(paltform_win, timer + 1, millisec, NULL)) { - return false; - } - return true; -} - -bool Platform::deactivate_interval_timer(TimerID timer) -{ - if (timer >= NUM_TIMERS) { - return false; - } - KillTimer(paltform_win, timer + 1); - return true; -} - -void Platform::destroy_interval_timer(TimerID timer) -{ - if (timer == INVALID_TIMER) { - return; - } - ASSERT(timer < NUM_TIMERS); - KillTimer(paltform_win, timer + 1); - free_timer(&timers[timer]); -} - uint64_t Platform::get_monolithic_time() { return uint64_t(GetTickCount()) * 1000 * 1000; @@ -565,9 +397,12 @@ bool Platform::is_monitors_pos_valid() void Platform::init() { - main_tread = GetCurrentThread(); create_message_wind(); - init_timers(); ... [truncated message content] |
From: Yaniv K. <yk...@re...> - 2009-12-30 20:17:39
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit d42620a3659e347db36ebb90b927c22d587cd024 Author: Arnon Gilboa <ag...@re...> Date: Wed Dec 30 14:04:01 2009 +0200 spice: PKG_CHECK_MODULES: CEGUI version diff --git a/configure.ac b/configure.ac index abba331..093588c 100644 --- a/configure.ac +++ b/configure.ac @@ -105,7 +105,7 @@ AC_SUBST(LOG4CPP_CFLAGS) AC_SUBST(LOG4CPP_LIBS) SPICE_REQUIRES+=" log4cpp" -PKG_CHECK_MODULES(CEGUI, CEGUI = 0.6.2) +PKG_CHECK_MODULES(CEGUI, CEGUI >= 0.6.0 CEGUI < 0.7.0) AC_SUBST(CEGUI_CFLAGS) AC_SUBST(CEGUI_LIBS) SPICE_REQUIRES+=" CEGUI" |
From: Yaniv K. <yk...@re...> - 2009-12-30 20:15:20
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit ea9af22e62fdae7fc0bd707ef60bcf82ec3c4551 Author: Arnon Gilboa <ag...@re...> Date: Wed Dec 30 13:41:58 2009 +0200 spice: position mouse in primary monitor center after full screen toggle -move _focused & _pointer_in_window from RedWindow to RedWindow_p's -move shadow focus & cursor handling to sync() -add reset_cursor_pos() to Platform -Monitor set_mode()/restore() use virtual do_set_mode()/do_restore() diff --git a/client/monitor.cpp b/client/monitor.cpp index 8526769..d56cfad 100644 --- a/client/monitor.cpp +++ b/client/monitor.cpp @@ -18,6 +18,7 @@ #include "common.h" #include "monitor.h" #include "debug.h" +#include "platform.h" uint32_t Monitor::self_monitors_change = 0; @@ -33,3 +34,13 @@ bool Monitor::is_self_change() return self_monitors_change != 0; } +void Monitor::set_mode(int width, int height) +{ + do_set_mode(width, height); + Platform::reset_cursor_pos(); +} +void Monitor::restore() +{ + do_restore(); + Platform::reset_cursor_pos(); +} diff --git a/client/monitor.h b/client/monitor.h index 59ec1e0..7a4ba3f 100644 --- a/client/monitor.h +++ b/client/monitor.h @@ -29,8 +29,8 @@ public: void set_free() {_free = true;} void set_used() {_free = false;} - virtual void set_mode(int width, int height) = 0; - virtual void restore() = 0; + void set_mode(int width, int height); + void restore(); virtual int get_depth() = 0; virtual Point get_position() = 0; virtual Point get_size() const = 0; @@ -41,6 +41,8 @@ public: protected: virtual ~Monitor() {} + virtual void do_set_mode(int width, int height) = 0; + virtual void do_restore() = 0; private: int _id; diff --git a/client/platform.h b/client/platform.h index 07777c0..1b4ef43 100644 --- a/client/platform.h +++ b/client/platform.h @@ -101,6 +101,8 @@ public: static uint32_t get_keyboard_modifiers(); + static void reset_cursor_pos(); + static LocalCursor* create_local_cursor(CursorData* cursor_data); static LocalCursor* create_inactive_cursor(); static LocalCursor* create_default_cursor(); diff --git a/client/red_window.h b/client/red_window.h index 5721c53..377d99b 100644 --- a/client/red_window.h +++ b/client/red_window.h @@ -105,8 +105,6 @@ private: Type _type; LocalCursor* _local_cursor; bool _cursor_visible; - bool _focused; - bool _pointer_in_window; bool _trace_key_interception; bool _key_interception_on; Menu* _menu; diff --git a/client/windows/platform.cpp b/client/windows/platform.cpp index 11f1326..3400811 100644 --- a/client/windows/platform.cpp +++ b/client/windows/platform.cpp @@ -227,8 +227,6 @@ class WinMonitor: public Monitor { public: WinMonitor(int id, const wchar_t* name, const wchar_t* string); - virtual void set_mode(int width, int height); - virtual void restore(); virtual int get_depth() { return _depth;} virtual Point get_position(); virtual Point get_size() const { Point size = {_width, _height}; return size;} @@ -237,6 +235,8 @@ public: protected: virtual ~WinMonitor(); + virtual void do_set_mode(int width, int height); + virtual void do_restore(); private: void update_position(); @@ -266,7 +266,7 @@ WinMonitor::WinMonitor(int id, const wchar_t* name, const wchar_t* string) WinMonitor::~WinMonitor() { - restore(); + do_restore(); } void WinMonitor::update_position() @@ -362,7 +362,7 @@ bool WinMonitor::best_display_setting(uint32_t width, uint32_t height, uint32_t == DISP_CHANGE_SUCCESSFUL; } -void WinMonitor::set_mode(int width, int height) +void WinMonitor::do_set_mode(int width, int height) { update_position(); if (width == _width && height == _height) { @@ -380,31 +380,37 @@ void WinMonitor::set_mode(int width, int height) update_position(); } -void WinMonitor::restore() +void WinMonitor::do_restore() { if (_active) { _active = false; self_monitors_change++; ChangeDisplaySettingsEx(_dev_name.c_str(), NULL, NULL, 0, NULL); self_monitors_change--; + update_position(); } } static MonitorsList monitors; +static Monitor* primary_monitor = NULL; const MonitorsList& Platform::init_monitors() { ASSERT(monitors.empty()); int id = 0; + Monitor* mon; DISPLAY_DEVICE device_info; DWORD device_id = 0; device_info.cb = sizeof(device_info); while (EnumDisplayDevices(NULL, device_id, &device_info, 0)) { if ((device_info.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) && - !(device_info.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) { - monitors.push_back(new WinMonitor(id++, device_info.DeviceName, - device_info.DeviceString)); + !(device_info.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) { + mon = new WinMonitor(id++, device_info.DeviceName, device_info.DeviceString); + monitors.push_back(mon); + if (device_info.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { + primary_monitor = mon; + } } device_id++; } @@ -413,6 +419,7 @@ const MonitorsList& Platform::init_monitors() void Platform::destroy_monitors() { + primary_monitor = NULL; while (!monitors.empty()) { Monitor* monitor = monitors.front(); monitors.pop_front(); @@ -507,6 +514,16 @@ uint32_t Platform::get_keyboard_modifiers() KEY_BIT(keymap, VK_RMENU, R_ALT_MODIFIER); } +void Platform::reset_cursor_pos() +{ + if (!primary_monitor) { + return; + } + Point pos = primary_monitor->get_position(); + Point size = primary_monitor->get_size(); + SetCursorPos(pos.x + size.x / 2, pos.y + size.y / 2); +} + class WinBaseLocalCursor: public LocalCursor { public: WinBaseLocalCursor() : _handle (0) {} diff --git a/client/windows/red_window.cpp b/client/windows/red_window.cpp index 14a7d29..4746719 100644 --- a/client/windows/red_window.cpp +++ b/client/windows/red_window.cpp @@ -327,6 +327,8 @@ RedWindow_p::RedWindow_p() , _modal_refs (0) , _no_taskmgr_dll (NULL) , _no_taskmgr_hook (NULL) + , _focused (false) + , _pointer_in_window (false) , _minimized (false) , _valid_pos (false) , _sys_menu (NULL) @@ -406,8 +408,6 @@ RedWindow::RedWindow(RedWindow::Listener& listener, int screen_id) , _type (TYPE_NORMAL) , _local_cursor (NULL) , _cursor_visible (true) - , _focused (false) - , _pointer_in_window (false) , _trace_key_interception (false) , _key_interception_on (false) , _menu (NULL) diff --git a/client/windows/red_window_p.h b/client/windows/red_window_p.h index 4b5655e..b35de57 100644 --- a/client/windows/red_window_p.h +++ b/client/windows/red_window_p.h @@ -56,6 +56,8 @@ protected: uint32_t _modal_refs; HMODULE _no_taskmgr_dll; HHOOK _no_taskmgr_hook; + bool _focused; + bool _pointer_in_window; bool _minimized; bool _valid_pos; int _x; diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp index 1a98e2e..77025b6 100644 --- a/client/x11/platform.cpp +++ b/client/x11/platform.cpp @@ -507,18 +507,20 @@ public: monitors.push_back(this); } - virtual void set_mode(int width, int height) - { - _out_of_sync = width > get_width() || height > get_height(); - } - - virtual void restore() {} virtual int get_depth() { return XPlatform::get_vinfo()[0]->depth;} virtual Point get_position() { return XScreen::get_position();} virtual Point get_size() const { Point pt = {get_width(), get_height()}; return pt;} virtual bool is_out_of_sync() { return _out_of_sync;} virtual int get_screen_id() { return get_screen();} +protected: + virtual void do_set_mode(int width, int height) + { + _out_of_sync = width > get_width() || height > get_height(); + } + + virtual void do_restore() {} + private: bool _out_of_sync; }; @@ -529,14 +531,16 @@ public: virtual ~DynamicScreen(); void publish_monitors(MonitorsList& monitors); - virtual void set_mode(int width, int height); - virtual void restore(); virtual int get_depth() { return XPlatform::get_vinfo()[0]->depth;} virtual Point get_position() { return XScreen::get_position();} virtual Point get_size() const { Point pt = {get_width(), get_height()}; return pt;} virtual bool is_out_of_sync() { return _out_of_sync;} virtual int get_screen_id() { return get_screen();} +protected: + virtual void do_set_mode(int width, int height); + virtual void do_restore(); + private: bool set_screen_size(int size_index); @@ -589,7 +593,7 @@ public: } }; -void DynamicScreen::set_mode(int width, int height) +void DynamicScreen::do_set_mode(int width, int height) { int num_sizes; @@ -611,7 +615,7 @@ void DynamicScreen::set_mode(int width, int height) X_DEBUG_SYNC(get_display()); } -void DynamicScreen::restore() +void DynamicScreen::do_restore() { X_DEBUG_SYNC(get_display()); if (is_broken() || (get_width() == _saved_width && get_height() == _saved_height)) { @@ -705,8 +709,6 @@ public: XMonitor(MultyMonScreen& container, int id, RRCrtc crtc); virtual ~XMonitor(); - virtual void set_mode(int width, int height); - virtual void restore(); virtual int get_depth(); virtual Point get_position(); virtual Point get_size() const; @@ -735,6 +737,10 @@ public: static void inc_change_ref() { Monitor::self_monitors_change++;} static void dec_change_ref() { Monitor::self_monitors_change--;} +protected: + virtual void do_set_mode(int width, int height); + virtual void do_restore(); + private: void update_position(); bool finde_mode_in_outputs(RRMode mode, int start_index, XRRScreenResources* res); @@ -1673,7 +1679,7 @@ XRRModeInfo* XMonitor::find_mode(int width, int height, XRRScreenResources* res) return NULL; } -void XMonitor::set_mode(int width, int height) +void XMonitor::do_set_mode(int width, int height) { if (width == _size.x && height == _size.y) { _out_of_sync = false; @@ -1759,12 +1765,12 @@ bool XMonitor::position_changed() return _position.x != _saved_position.x || _position.y != _saved_position.y; } -void XMonitor::restore() +void XMonitor::do_restore() { if (!mode_changed()) { return; } - set_mode(_saved_size.x, _saved_size.y); + do_set_mode(_saved_size.x, _saved_size.y); } int XMonitor::get_depth() @@ -1847,6 +1853,7 @@ void XMonitor::set_mode(const XRRModeInfo& mode) #endif static MonitorsList monitors; +static Monitor* primary_monitor = NULL; typedef std::list<XScreen*> ScreenList; static ScreenList screens; @@ -1877,11 +1884,20 @@ const MonitorsList& Platform::init_monitors() for (; iter != screens.end(); iter++) { (*iter)->publish_monitors(monitors); } + MonitorsList::iterator mon_iter = monitors.begin(); + for (; mon_iter != monitors.end(); mon_iter++) { + Monitor *mon = *mon_iter; + if (mon->get_id() == 0) { + primary_monitor = mon; + break; + } + } return monitors; } void Platform::destroy_monitors() { + primary_monitor = NULL; monitors.clear(); while (!screens.empty()) { XScreen* screen = screens.front(); @@ -2295,6 +2311,17 @@ uint32_t Platform::get_keyboard_modifiers() key_bit(keymap, XK_Alt_R, R_ALT_MODIFIER); } +void Platform::reset_cursor_pos() +{ + if (!primary_monitor) { + return; + } + Point pos = primary_monitor->get_position(); + Point size = primary_monitor->get_size(); + Window root_window = RootWindow(x_display, DefaultScreen(x_display)); + XWarpPointer(x_display, None, root_window, 0, 0, 0, 0, pos.x + size.x / 2, pos.y + size.y / 2); +} + WaveRecordAbstract* Platform::create_recorder(RecordClient& client, uint32_t sampels_per_sec, uint32_t bits_per_sample, diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp index ee43b5a..795a7bb 100644 --- a/client/x11/red_window.cpp +++ b/client/x11/red_window.cpp @@ -889,7 +889,7 @@ void RedWindow_p::win_proc(XEvent& event) if (!red_window->_ignore_pointer) { 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)); + to_red_buttons_state(event.xcrossing.state)); } else { red_window->_shadow_pointer_state = true; memcpy(&red_window->_shadow_pointer_event, &event, sizeof(XEvent)); @@ -906,13 +906,35 @@ void RedWindow_p::win_proc(XEvent& event) } } -void RedWindow_p::sync() +void RedWindow_p::sync(bool shadowed) { + if (shadowed) { + _ignore_foucs = true; + _ignore_pointer = true; + _shadow_foucs_state = _focused; + _shadow_pointer_state = _pointer_in_window; + _shadow_focus_event.xany.serial = 0; + } XSync(x_display, False); XEvent event; while (XCheckWindowEvent(x_display, _win, ~long(0), &event)) { win_proc(event); } + if (!shadowed) { + return; + } + _ignore_foucs = false; + _ignore_pointer = false; + if (_shadow_foucs_state != _focused) { + DBG(0, "put back shadowed focus event"); + XPutBackEvent(x_display, &_shadow_focus_event); + } else if (_shadow_focus_event.xany.serial > 0) { + focus_serial = _shadow_focus_event.xany.serial; + } + if (_shadow_pointer_state != _pointer_in_window) { + DBG(0, "put back shadowed pointer event"); + XPutBackEvent(x_display, &_shadow_pointer_event); + } } void RedWindow_p::wait_for_reparent() @@ -1023,7 +1045,9 @@ RedWindow_p::RedWindow_p() : _win (None) , _glcont_copy (NULL) , _icon (NULL) + , _focused (false) , _ignore_foucs (false) + , _pointer_in_window (false) , _ignore_pointer (false) { } @@ -1193,8 +1217,6 @@ RedWindow::RedWindow(RedWindow::Listener& listener, int screen) , _type (TYPE_NORMAL) , _local_cursor (NULL) , _cursor_visible (true) - , _focused (false) - , _pointer_in_window (false) , _trace_key_interception (false) , _key_interception_on (false) , _menu (NULL) @@ -1600,55 +1622,18 @@ void RedWindow::do_start_key_interception() // LeaveNotify and EnterNotify. ASSERT(_focused); - _ignore_foucs = true; - _ignore_pointer = true; - _shadow_foucs_state = true; - _shadow_pointer_state = true; - _shadow_focus_event.xany.serial = 0; XGrabKeyboard(x_display, _win, True, GrabModeAsync, GrabModeAsync, CurrentTime); - sync(); + sync(true); _listener.on_start_key_interception(); - _ignore_foucs = false; - _ignore_pointer = false; _key_interception_on = true; - if (!_shadow_foucs_state) { - DBG(0, "put back shadowed focus out"); - XPutBackEvent(x_display, &_shadow_focus_event); - } else if (_shadow_focus_event.xany.serial > 0) { - ASSERT(focus_window == this); - focus_serial = _shadow_focus_event.xany.serial; - } - - if (!_shadow_pointer_state) { - DBG(0, "put back shadowed pointer leave"); - XPutBackEvent(x_display, &_shadow_pointer_event); - } } void RedWindow::do_stop_key_interception() { - _ignore_foucs = true; - _ignore_pointer = true; - _shadow_foucs_state = _focused; - _shadow_pointer_state = _pointer_in_window; - _shadow_focus_event.xany.serial = 0; XUngrabKeyboard(x_display, CurrentTime); - sync(); + sync(true); _key_interception_on = false; _listener.on_stop_key_interception(); - _ignore_foucs = false; - _ignore_pointer = false; - if (_shadow_foucs_state != _focused) { - DBG(0, "put back shadowed focus event"); - XPutBackEvent(x_display, &_shadow_focus_event); - } else if (_shadow_focus_event.xany.serial > 0) { - focus_serial = _shadow_focus_event.xany.serial; - } - - if (_shadow_pointer_state != _pointer_in_window) { - DBG(0, "put back shadowed pointer event"); - XPutBackEvent(x_display, &_shadow_pointer_event); - } } void RedWindow::start_key_interception() @@ -1705,7 +1690,7 @@ void RedWindow::hide_cursor() void RedWindow::release_mouse() { XUngrabPointer(x_display, CurrentTime); - sync(); + sync(true); } void RedWindow::cupture_mouse() diff --git a/client/x11/red_window_p.h b/client/x11/red_window_p.h index 77933f9..df30634 100644 --- a/client/x11/red_window_p.h +++ b/client/x11/red_window_p.h @@ -41,7 +41,7 @@ public: void wait_for_reparent(); void wait_for_map(); void wait_for_unmap(); - void sync(); + void sync(bool shadowed = false); void set_visibale(bool vis) { _visibale = vis;} void move_to_current_desktop(); Window get_window() {return _win;} @@ -61,9 +61,11 @@ protected: Point _show_pos; GLXContext _glcont_copy; Icon* _icon; + bool _focused; bool _ignore_foucs; bool _shadow_foucs_state; XEvent _shadow_focus_event; + bool _pointer_in_window; bool _ignore_pointer; bool _shadow_pointer_state; XEvent _shadow_pointer_event; |
From: Yaniv K. <yk...@re...> - 2009-12-30 20:09:40
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit 02a07b2c067e629749cbe8a9f9cfbfb487a512d7 Author: Arnon Gilboa <ag...@re...> Date: Wed Dec 30 12:19:54 2009 +0200 spice: on_activate_screen generates on_key_down for any modifier pressed -call SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc...) only once, in RedWindow::init() -add Application::cleanup_globals() & RedWindow::cleanup() -cleanup LowLevelKeyboardProc() diff --git a/client/application.cpp b/client/application.cpp index 2f24307..ac5877c 100644 --- a/client/application.cpp +++ b/client/application.cpp @@ -1062,6 +1062,32 @@ void Application::reset_sticky() _sticky_info.key = REDKEY_INVALID; } +struct ModifierKey { + int modifier; + RedKey key; +}; + +ModifierKey modifier_keys[] = { + {Platform::L_SHIFT_MODIFIER, REDKEY_L_SHIFT}, + {Platform::R_SHIFT_MODIFIER, REDKEY_R_SHIFT}, + {Platform::L_CTRL_MODIFIER, REDKEY_L_CTRL}, + {Platform::R_CTRL_MODIFIER, REDKEY_R_CTRL}, + {Platform::L_ALT_MODIFIER, REDKEY_L_ALT}, + {Platform::R_ALT_MODIFIER, REDKEY_R_ALT}, +}; + +void Application::sync_keyboard_modifiers() +{ + uint32_t modifiers = Platform::get_keyboard_modifiers(); + for (int i = 0; i < sizeof(modifier_keys) / sizeof(modifier_keys[0]); i++) { + if (modifiers & modifier_keys[i].modifier) { + on_key_down(modifier_keys[i].key); + } else { + on_key_up(modifier_keys[i].key); + } + } +} + void Application::on_key_down(RedKey key) { if (key <= 0 || key >= REDKEY_NUM_KEYS) { @@ -1179,6 +1205,7 @@ void Application::on_activate_screen(RedScreen* screen) { ASSERT(!_active_screen || (_active_screen == screen)); _active_screen = screen; + sync_keyboard_modifiers(); } void Application::on_start_screen_key_interception(RedScreen* screen) @@ -1380,6 +1407,7 @@ void Application::exit_full_screen() return; } LOG_INFO(""); + _changing_screens = true; release_capture(); for (int i = 0; i < (int)_screens.size(); i++) { if (_screens[i]) { @@ -1396,27 +1424,16 @@ void Application::exit_full_screen() restore_screens_size(); show(); _main_screen->activate(); + _changing_screens = false; } bool Application::toggle_full_screen() { - RedKey shift_pressed = REDKEY_INVALID; - - if (_keyboard_state[REDKEY_L_SHIFT]) { - shift_pressed = REDKEY_L_SHIFT; - } else if (_keyboard_state[REDKEY_R_SHIFT]) { - shift_pressed = REDKEY_R_SHIFT; - } if (_full_screen) { exit_full_screen(); } else { enter_full_screen(); } - uint32_t modifiers = Platform::get_keyboard_modifiers(); - if ((shift_pressed == REDKEY_L_SHIFT && (modifiers & Platform::L_SHIFT_MODIFIER)) || - (shift_pressed == REDKEY_R_SHIFT && (modifiers & Platform::R_SHIFT_MODIFIER))) { - on_key_down(shift_pressed); - } return _full_screen; } @@ -1978,15 +1995,25 @@ void Application::init_globals() RedWindow::init(); } +void Application::cleanup_globals() +{ + RedWindow::cleanup(); +} + int Application::main(int argc, char** argv, const char* version_str) { + int ret; + init_globals(); LOG_INFO("starting %s", version_str); std::auto_ptr<Application> app(new Application()); AutoAbort auto_abort(*app.get()); - if (!app->process_cmd_line(argc, argv)) { - return app->_exit_code; + if (app->process_cmd_line(argc, argv)) { + ret = app->run(); + } else { + ret = app->_exit_code; } - return app->run(); + cleanup_globals(); + return ret; } diff --git a/client/application.h b/client/application.h index 5c60702..5fa9335 100644 --- a/client/application.h +++ b/client/application.h @@ -265,9 +265,11 @@ private: bool unpress_key(RedKey key); void reset_sticky(); static bool is_sticky_trace_key(RedKey key); + void sync_keyboard_modifiers(); static void init_logger(); static void init_globals(); + static void cleanup_globals(); friend class DisconnectedEvent; friend class ConnectionErrorEvent; diff --git a/client/red_window.h b/client/red_window.h index 3c7ac77..5721c53 100644 --- a/client/red_window.h +++ b/client/red_window.h @@ -86,6 +86,7 @@ public: void unset_type_gl(); static void init(); + static void cleanup(); Listener& get_listener() { return _listener;} diff --git a/client/windows/red_window.cpp b/client/windows/red_window.cpp index 8716b07..14a7d29 100644 --- a/client/windows/red_window.cpp +++ b/client/windows/red_window.cpp @@ -35,6 +35,7 @@ static ATOM class_atom = 0; static const LPCWSTR win_class_name = L"redc_wclass"; static HWND focus_window = NULL; static HHOOK low_keyboard_hook = NULL; +static bool low_keyboard_hook_on = false; static HHOOK msg_filter_hook = NULL; typedef std::list<RedKey> KeysList; static KeysList filtered_up_keys; @@ -714,30 +715,14 @@ Point RedWindow::get_size() static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { - if ((nCode == HC_ACTION)) { + if (low_keyboard_hook_on && focus_window && nCode == HC_ACTION) { KBDLLHOOKSTRUCT *hooked = (KBDLLHOOKSTRUCT*)lParam; - DWORD dwMsg = 1; - - // dwMsg shall contain the information that would be stored - // in the usual lParam argument of a WM_KEYDOWN message. - // All information like hardware scan code and other flags - // are stored within one double word at different bit offsets. - // Refer to MSDN for further information: - // - // (Keystroke Messages) - dwMsg += hooked->scanCode << 16; - dwMsg += hooked->flags << 24; - - // In some cases scan code of VK_RSHIFT is fake shift (probably a bug) so we - // convert it to non extended code. Also, QEmu doesn't expect num-lock to be - // an extended key. - if ((hooked->vkCode == VK_NUMLOCK) || (hooked->vkCode == VK_RSHIFT)) { + DWORD dwMsg = (hooked->flags << 24) | (hooked->scanCode << 16) | 1; + + if (hooked->vkCode == VK_NUMLOCK || hooked->vkCode == VK_RSHIFT) { dwMsg &= ~(1 << 24); + SendMessage(focus_window, wParam, hooked->vkCode, dwMsg); } - - SendMessage(focus_window, wParam, hooked->vkCode, dwMsg); - - // Forward all modifier key strokes to update keyboard leds & shift/ctrl/alt state switch (hooked->vkCode) { case VK_CAPITAL: case VK_SCROLL: @@ -750,34 +735,25 @@ static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lP case VK_RMENU: break; default: + SendMessage(focus_window, wParam, hooked->vkCode, dwMsg); return 1; } } - - // In all other cases, we call the next hook and return it's value. return CallNextHookEx(NULL, nCode, wParam, lParam); } void RedWindow::do_start_key_interception() { + low_keyboard_hook_on = true; _key_interception_on = true; _listener.on_start_key_interception(); - if (low_keyboard_hook) { - return; - } - low_keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, - GetModuleHandle(NULL), 0); } void RedWindow::do_stop_key_interception() { + low_keyboard_hook_on = false; _key_interception_on = false; _listener.on_stop_key_interception(); - if (!low_keyboard_hook) { - return; - } - UnhookWindowsHookEx(low_keyboard_hook); - low_keyboard_hook = NULL; } void RedWindow::start_key_interception() @@ -807,6 +783,13 @@ void RedWindow::init() if (!(class_atom = register_class(instance))) { THROW("register class failed"); } + low_keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, + GetModuleHandle(NULL), 0); +} + +void RedWindow::cleanup() +{ + UnhookWindowsHookEx(low_keyboard_hook); } #ifdef USE_OGL @@ -850,6 +833,7 @@ void RedWindow::on_focus_out() } _focused = false; + focus_window = NULL; if (_key_interception_on) { do_stop_key_interception(); diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp index 2f17cb1..ee43b5a 100644 --- a/client/x11/red_window.cpp +++ b/client/x11/red_window.cpp @@ -2046,3 +2046,7 @@ void RedWindow::init() #endif } +void RedWindow::cleanup() +{ +} + |
From: Yaniv K. <yk...@re...> - 2009-12-30 19:35:05
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: 0.4 commit 83efc81f30b4625f40983a5771cfdccc5860f8e6 Author: Yaniv Kamay <yk...@re...> Date: Wed Dec 30 21:32:06 2009 +0200 move to intermediate version 0.4.1 diff --git a/client/windows/redc.rc b/client/windows/redc.rc index 916d5a1..cf0ef17 100644 --- a/client/windows/redc.rc +++ b/client/windows/redc.rc @@ -61,8 +61,8 @@ INFO_IMAGE_RES_ID BITMAP "static_title.bmp" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,4,0,0 - PRODUCTVERSION 0,4,0,0 + FILEVERSION 0,4,1,0 + PRODUCTVERSION 0,4,1,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -79,12 +79,12 @@ BEGIN BEGIN VALUE "CompanyName", "Red Hat Inc." VALUE "FileDescription", "Spice client" - VALUE "FileVersion", "0, 4, 0, 0" + VALUE "FileVersion", "0, 4, 1, 0" VALUE "InternalName", "spicec" VALUE "LegalCopyright", "Copyright (c) 2009 Red Hat, Inc. and/or its affiliates." VALUE "OriginalFilename", "spicec.exe" VALUE "ProductName", "Red Hat Spice" - VALUE "ProductVersion", "0, 4, 0, 0" + VALUE "ProductVersion", "0, 4, 1, 0" END END BLOCK "VarFileInfo" diff --git a/configure.ac b/configure.ac index cfdd316..43b8ec6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.57]) m4_define([SPICE_MAJOR], 0) m4_define([SPICE_MINOR], 4) -m4_define([SPICE_MICRO], 0) +m4_define([SPICE_MICRO], 1) AC_INIT(spice, [SPICE_MAJOR.SPICE_MINOR.SPICE_MICRO], [], spice) |
From: Yaniv K. <yk...@re...> - 2009-12-28 14:44:47
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit c57bcf6f4433446b858867712ece4abec4fb5c3d Author: Yaniv Kamay <yk...@re...> Date: Mon Dec 28 16:39:00 2009 +0200 client: let PreLoginDialog save and restore LoginDialog diff --git a/client/gui/gui.cpp b/client/gui/gui.cpp index 1bbf3c4..4a63d5a 100644 --- a/client/gui/gui.cpp +++ b/client/gui/gui.cpp @@ -212,6 +212,7 @@ public: CEGUI::System& gui_system() { return _gui.gui_system();} void set_dialog(Dialog* dialog) { _gui.set_dialog(dialog);} + void dettach() { _gui.dettach_dialog(this);} TabFactorys& get_factoris() { return _gui._tab_factorys;} bool message_box(MessageType type, const char *text, const ButtonsList& buttons, @@ -481,14 +482,19 @@ private: class PreLoginDialog: public TabDialog { public: - PreLoginDialog(GUI& gui); + PreLoginDialog(GUI& gui, LoginDialog* login_dialog); + virtual ~PreLoginDialog() { delete _login_dialog;} bool handle_back(const CEGUI::EventArgs& e); bool handle_quit(const CEGUI::EventArgs& e); + +private: + LoginDialog* _login_dialog; }; -PreLoginDialog::PreLoginDialog(GUI& gui) +PreLoginDialog::PreLoginDialog(GUI& gui, LoginDialog* login_dialog) : TabDialog(gui, false) + , _login_dialog (login_dialog) { try { @@ -509,7 +515,10 @@ PreLoginDialog::PreLoginDialog(GUI& gui) bool PreLoginDialog::handle_back(const CEGUI::EventArgs& e) { - set_dialog(new LoginDialog(_gui)); + ASSERT(_login_dialog); + LoginDialog* login_dialog = _login_dialog; + _login_dialog = NULL; + set_dialog(login_dialog); return true; } @@ -675,7 +684,8 @@ bool LoginDialog::handle_quit(const CEGUI::EventArgs& e) bool LoginDialog::handle_options(const CEGUI::EventArgs& e) { - set_dialog(new PreLoginDialog(_gui)); + dettach(); + set_dialog(new PreLoginDialog(_gui, this)); return true; } @@ -1054,6 +1064,16 @@ void GUI::set_dialog(Dialog* dialog) update_layer_area(); } +void GUI::dettach_dialog(Dialog* dialog) +{ + if (!dialog || _dialog != dialog) { + return; + } + gui_system().setGUISheet(NULL); + _dialog = NULL; + update_layer_area(); +} + void GUI::create_dialog() { switch (_state) { diff --git a/client/gui/gui.h b/client/gui/gui.h index 2e505b0..fd7e56a 100644 --- a/client/gui/gui.h +++ b/client/gui/gui.h @@ -81,6 +81,7 @@ private: void init_cegui(); void conditional_update(); void set_dialog(Dialog* dialog); + void dettach_dialog(Dialog* dialog); private: Application& _app; |
From: Yaniv K. <yk...@re...> - 2009-12-28 13:11:01
|
repository: /home/tlv/ykamay/open_spice_upload/slirp branch: master commit 35e4bb21660357c5ae73ea5e40c504b8d190ab95 Author: Jeroen van Meeuwen (Fedora Unity) <ka...@fe...> Date: Mon Dec 28 01:11:27 2009 +0100 Make sure make install DESTDIR=/path/to actually works diff --git a/Makefile b/Makefile index 9dd62d2..929af78 100644 --- a/Makefile +++ b/Makefile @@ -81,11 +81,11 @@ $(TARGETNAME): -include $(patsubst %.c, $(TARGETNAME)/.%.dep, $(SRCS)) install: - mkdir -p $(INCLUDEDIR) - cp $(LIBNAME) $(LIBDIR) - cp $(HEADERNAME) $(INCLUDEDIR) - cp $(PCNAME) $(PKGCONFIGDIR) + mkdir -p $(DESTDIR)/$(INCLUDEDIR) + cp $(LIBNAME) $(DESTDIR)/$(LIBDIR) + cp $(HEADERNAME) $(DESTDIR)/$(INCLUDEDIR) + cp $(PCNAME) $(DESTDIR)/$(PKGCONFIGDIR) uninstall: - rm -f $(LIBDIR)/$(LIBNAME) - rm -f $(INCLUDEDIR)/$(HEADERNAME) - rm -f $(PKGCONFIGDIR)/$(PCNAME) + rm -f $(DESTDIR)/$(LIBDIR)/$(LIBNAME) + rm -f $(DESTDIR)/$(INCLUDEDIR)/$(HEADERNAME) + rm -f $(DESTDIR)/$(PKGCONFIGDIR)/$(PCNAME) |
From: Yaniv K. <yk...@re...> - 2009-12-28 10:39:14
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit 68fb44012982897ea883b336c56d0e8c12ddce0d Author: Yaniv Kamay <yk...@re...> Date: Mon Dec 28 01:15:08 2009 +0200 client: add GUI infrastructure + functional login dialog diff --git a/client/application.cpp b/client/application.cpp index e96a9c4..2f24307 100644 --- a/client/application.cpp +++ b/client/application.cpp @@ -42,6 +42,7 @@ #include "cmd_line_parser.h" #include "tunnel_channel.h" #include "rect.h" +#include "gui/gui.h" #include <log4cpp/BasicConfigurator.hh> #include <log4cpp/FileAppender.hh> @@ -85,54 +86,86 @@ void MonitorsQuery::do_response(AbstractProcessLoop& events_loop) } } -class GUILayer: public ScreenLayer { +//todo: add inactive visual appearance +class GUIBarrier: public ScreenLayer { public: - GUILayer(); + GUIBarrier(int id) + : ScreenLayer(SCREEN_LAYER_GUI_BARIER, true) + , _id (id) + , _cursor (Platform::create_inactive_cursor()) + { + } + + ~GUIBarrier() + { + detach(); + } + + int get_id() { return _id;} + + void attach(RedScreen& in_screen) + { + if (screen()) { + ASSERT(&in_screen == screen()) + return; + } + in_screen.attach_layer(*this); + } + + void detach() + { + if (!screen()) { + return; + } + screen()->detach_layer(*this); + } + + virtual bool pointer_test(int x, int y) { return true;} + virtual void on_pointer_enter(int x, int y, unsigned int buttons_state) + { + AutoRef<LocalCursor> cursor(Platform::create_inactive_cursor()); + screen()->set_cursor(*cursor); + return; + } + +private: + int _id; + AutoRef<LocalCursor> _cursor; +}; + +class InfoLayer: public ScreenLayer { +public: + InfoLayer(); virtual void copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc); - void set_splash_mode(); void set_info_mode(); void set_sticky(bool is_on); virtual void on_size_changed(); private: - void draw_splash(const QRegion& dest_region, RedDrawable& dest); void draw_info(const QRegion& dest_region, RedDrawable& dest); + void update_sticky_rect(); private: - ImageFromRes _splash_pixmap; AlphaImageFromRes _info_pixmap; AlphaImageFromRes _sticky_pixmap; - Point _splash_pos; Point _info_pos; Point _sticky_pos; Rect _sticky_rect; - bool _splash_mode; bool _sticky_on; RecurciveMutex _update_lock; }; -GUILayer::GUILayer() - : ScreenLayer(SCREEN_LAYER_GUI, false) - , _splash_pixmap (SPLASH_IMAGE_RES_ID) +InfoLayer::InfoLayer() + : ScreenLayer(SCREEN_LAYER_INFO, false) , _info_pixmap (INFO_IMAGE_RES_ID) , _sticky_pixmap (STICKY_KEY_PIXMAP) - , _splash_mode (false) , _sticky_on (false) { } -void GUILayer::draw_splash(const QRegion& dest_region, RedDrawable& dest) -{ - ASSERT(!_sticky_on); - for (int i = 0; i < (int)dest_region.num_rects; i++) { - Rect* r = &dest_region.rects[i]; - dest.copy_pixels(_splash_pixmap, r->left - _splash_pos.x, r->top - _splash_pos.y, *r); - } -} - -void GUILayer::draw_info(const QRegion& dest_region, RedDrawable& dest) +void InfoLayer::draw_info(const QRegion& dest_region, RedDrawable& dest) { for (int i = 0; i < (int)dest_region.num_rects; i++) { Rect* r = &dest_region.rects[i]; @@ -145,36 +178,18 @@ void GUILayer::draw_info(const QRegion& dest_region, RedDrawable& dest) } } -void GUILayer::copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc) +void InfoLayer::copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc) { RecurciveLock lock(_update_lock); - if (_splash_mode) { - draw_splash(dest_region, dest_dc); - } else { - draw_info(dest_region, dest_dc); - } + draw_info(dest_region, dest_dc); } -void GUILayer::set_splash_mode() +void InfoLayer::set_info_mode() { RecurciveLock lock(_update_lock); - Point size = _splash_pixmap.get_size(); - Point screen_size = screen()->get_size(); - Rect r; - _splash_pos.y = r.top = (screen_size.y - size.y) / 2; - _splash_pos.x = r.left = (screen_size.x - size.x) / 2; - r.bottom = r.top + size.y; - r.right = r.left + size.x; - _splash_mode = true; - lock.unlock(); - set_rect_area(r); - ASSERT(!_sticky_on); -} + ASSERT(screen()); -void GUILayer::set_info_mode() -{ - RecurciveLock lock(_update_lock); Point size = _info_pixmap.get_size(); Point screen_size = screen()->get_size(); Rect r; @@ -184,45 +199,45 @@ void GUILayer::set_info_mode() _info_pos.x = r.right - size.x; _info_pos.y = r.top = 0; r.bottom = r.top + size.y; - _splash_mode = false; lock.unlock(); set_rect_area(r); - + update_sticky_rect(); set_sticky(_sticky_on); } -void GUILayer::set_sticky(bool is_on) +void InfoLayer::update_sticky_rect() +{ + Point size = _sticky_pixmap.get_size(); + Point screen_size = screen()->get_size(); + + _sticky_pos.x = (screen_size.x - size.x) / 2; + _sticky_pos.y = screen_size.y * 2 / 3; + _sticky_rect.left = _sticky_pos.x; + _sticky_rect.top = _sticky_pos.y; + _sticky_rect.right = _sticky_rect.left + size.x; + _sticky_rect.bottom = _sticky_rect.top + size.y; +} + +void InfoLayer::set_sticky(bool is_on) { RecurciveLock lock(_update_lock); if (!_sticky_on && !is_on) { return; } - Point size = _sticky_pixmap.get_size(); - Point screen_size = screen()->get_size(); - _sticky_on = is_on; + if (_sticky_on) { - _sticky_pos.x = (screen_size.x - size.x) / 2; - _sticky_pos.y = screen_size.y * 2 / 3; - _sticky_rect.left = _sticky_pos.x; - _sticky_rect.top = _sticky_pos.y; - _sticky_rect.right = _sticky_rect.left + size.x; - _sticky_rect.bottom = _sticky_rect.top + size.y; add_rect_area(_sticky_rect); - invalidate(); + invalidate(_sticky_rect); } else { remove_rect_area(_sticky_rect); } } -void GUILayer::on_size_changed() +void InfoLayer::on_size_changed() { - if (_splash_mode) { - set_splash_mode(); - } else { - set_info_mode(); - } + set_info_mode(); } void StickyKeyTimer::response(AbstractProcessLoop& events_loop) @@ -235,10 +250,46 @@ void StickyKeyTimer::response(AbstractProcessLoop& events_loop) ASSERT(sticky_info->key_down); sticky_info->sticky_mode = true; DBG(0, "ON sticky"); - app->_gui_layer->set_sticky(true); + app->_info_layer->set_sticky(true); app->deactivate_interval_timer(this); } +class GUITimer: public Timer { +public: + GUITimer(GUI& gui) + : _gui (gui) + { + } + + virtual void response(AbstractProcessLoop& events_loop) + { + _gui.idle(); + } + +private: + GUI& _gui; +}; + + +#ifdef GUI_DEMO +class TestTimer: public Timer { +public: + TestTimer(Application& app) + : _app (app) + { + } + + virtual void response(AbstractProcessLoop& events_loop) + { + _app.message_box_test(); + } + +private: + Application& _app; +}; +#endif + + static MouseHandler default_mouse_handler; static KeyHandler default_key_handler; @@ -254,6 +305,7 @@ enum AppCommands { APP_CMD_CONNECT, APP_CMD_DISCONNECT, #endif + APP_CMD_SHOW_GUI, }; Application::Application() @@ -267,13 +319,14 @@ Application::Application() , _exit_code (0) , _active_screen (NULL) , _num_keys_pressed (0) - , _gui_layer (new GUILayer()) + , _info_layer (new InfoLayer()) , _key_handler (&default_key_handler) , _mouse_handler (&default_mouse_handler) , _monitors (NULL) , _title (L"SPICEc:%d") - , _splash_mode (true) , _sys_key_intercept_mode (false) + , _gui_mode (GUI_MODE_FULL) + , _state (DISCONNECTED) { DBG(0, ""); Platform::set_process_loop(*this); @@ -281,8 +334,6 @@ Application::Application() memset(_keyboard_state, 0, sizeof(_keyboard_state)); init_menu(); _main_screen = get_screen(0); - _main_screen->attach_layer(*_gui_layer); - _gui_layer->set_splash_mode(); Platform::set_event_listener(this); Platform::set_display_mode_listner(this); @@ -293,6 +344,7 @@ Application::Application() _commands_map["connect"] = APP_CMD_CONNECT; _commands_map["disconnect"] = APP_CMD_DISCONNECT; #endif + _commands_map["show-gui"] = APP_CMD_SHOW_GUI; _canvas_types.resize(1); #ifdef WIN32 @@ -307,6 +359,7 @@ Application::Application() ",connect=shift+f5" ",disconnect=shift+f6" #endif + ",show-gui=shift+f7" , _commands_map)); _hot_keys = parser->get(); @@ -316,11 +369,32 @@ Application::Application() _sticky_info.key_down = false; _sticky_info.key = REDKEY_INVALID; _sticky_info.timer.reset(new StickyKeyTimer()); + + _gui.reset(new GUI(*this, DISCONNECTED)); + _gui_timer.reset(new GUITimer(*_gui.get())); + activate_interval_timer(*_gui_timer, 1000 / 30); +#ifdef GUI_DEMO + _gui_test_timer.reset(new TestTimer(*this)); + activate_interval_timer(*_gui_test_timer, 1000 * 30); +#endif + for (int i = RED_CHANNEL_MAIN; i < RED_CHANNEL_END; i++) { + _peer_con_opt[i] = RedPeer::ConnectionOptions::CON_OP_BOTH; + } } Application::~Application() { - _main_screen->detach_layer(*_gui_layer); + deactivate_interval_timer(*_gui_timer); +#ifdef GUI_DEMO + deactivate_interval_timer(*_gui_test_timer); +#endif + destroyed_gui_barriers(); + _gui->set_screen(NULL); + + if (_info_layer->screen()) { + _main_screen->detach_layer(*_info_layer); + } + _main_screen->unref(); destroy_monitors(); } @@ -405,7 +479,7 @@ void Application::remove_mouse_handler(MouseHandler& handler) void Application::capture_mouse() { - if (!_active_screen) { + if (!_active_screen || _gui->screen()) { return; } _active_screen->capture_mouse(); @@ -441,15 +515,20 @@ private: void Application::connect() { + ASSERT(_state == DISCONNECTED); + set_state(CONNECTING); _client.connect(); } int Application::run() { - _client.connect(); - _exit_code = ProcessLoop::run(); - return _exit_code; + if (_gui_mode != GUI_MODE_FULL) { + connect(); + } + show_gui(); + _exit_code = ProcessLoop::run(); + return _exit_code; } RedScreen* Application::find_screen(int id) @@ -505,6 +584,7 @@ RedScreen* Application::get_screen(int id) size.y = SCREEN_INIT_HEIGHT; } screen = _screens[id] = new RedScreen(*this, id, _title, size.x, size.y); + create_gui_barrier(*screen, id); if (id != 0) { if (_full_screen) { @@ -532,10 +612,65 @@ RedScreen* Application::get_screen(int id) return screen; } +void Application::attach_gui_barriers() +{ + GUIBarriers::iterator iter = _gui_barriers.begin(); + + for (; iter != _gui_barriers.end(); iter++) { + GUIBarrier* barrier = *iter; + ASSERT((int)_screens.size() > barrier->get_id() && _screens[barrier->get_id()]); + barrier->attach(*_screens[barrier->get_id()]); + } +} + +void Application::detach_gui_barriers() +{ + GUIBarriers::iterator iter = _gui_barriers.begin(); + + for (; iter != _gui_barriers.end(); iter++) { + GUIBarrier* barrier = *iter; + barrier->detach(); + } +} + +void Application::create_gui_barrier(RedScreen& screen, int id) +{ + GUIBarrier* barrier = new GUIBarrier(id); + _gui_barriers.push_front(barrier); + if (_gui.get() && _gui->screen()) { + barrier->attach(screen); + } +} + +void Application::destroyed_gui_barriers() +{ + while (_gui_barriers.begin() != _gui_barriers.end()) { + GUIBarrier* barrier = *_gui_barriers.begin(); + _gui_barriers.erase(_gui_barriers.begin()); + delete barrier; + } +} + +void Application::destroyed_gui_barrier(int id) +{ + GUIBarriers::iterator iter = _gui_barriers.begin(); + + for (; iter != _gui_barriers.end(); iter++) { + GUIBarrier* barrier = *iter; + if (barrier->get_id() == id) { + _gui_barriers.erase(iter); + delete barrier; + return; + } + } +} + void Application::on_screen_destroyed(int id, bool was_captured) { bool reposition = false; + destroyed_gui_barrier(id); + if ((int)_screens.size() < id + 1 || !_screens[id]) { THROW("no screen"); } @@ -585,18 +720,32 @@ void Application::unpress_all() } } -void Application::on_connected() +void Application::set_state(State state) { + if (state == _state) { + return; + } + _state = state; + _gui->set_state(_state); + if (_gui->screen() && !_gui->is_visible()) { + hide_gui(); + } + reset_sticky(); +} +void Application::on_connected() +{ + set_state(CONNECTED); } void Application::on_disconnected(int error_code) { -#ifdef RED_DEBUG - show_splash(0); -#else - do_quit(error_code); -#endif + if (_gui_mode != GUI_MODE_FULL) { + ProcessLoop::quit(error_code); + return; + } + set_state(DISCONNECTED); + show_gui(); } void Application::on_visibility_start(int screen_id) @@ -604,8 +753,8 @@ void Application::on_visibility_start(int screen_id) if (screen_id) { return; } - - hide_splash(0); + set_state(VISIBILITY); + hide_gui(); } void Application::on_disconnecting() @@ -621,6 +770,88 @@ Menu* Application::get_app_menu() return (*_app_menu)->ref(); } +void Application::show_info_layer() +{ + if (_info_layer->screen() || _state != VISIBILITY) { + return; + } + + _main_screen->attach_layer(*_info_layer); + _info_layer->set_info_mode(); + reset_sticky(); +} + +void Application::hide_info_layer() +{ + if (!_info_layer->screen()) { + return; + } + + _main_screen->detach_layer(*_info_layer); + reset_sticky(); +} + +#ifdef GUI_DEMO + +class TestResponce: public GUI::BoxResponse { +public: + virtual void response(int response) + { + DBG(0, "%d", response); + } + + virtual void aborted() + { + DBG(0, ""); + } +}; + + +TestResponce response_test; + +void Application::message_box_test() +{ + GUI::ButtonsList list(3); + list[0].id = 101; + list[0].text = "Yes"; + list[1].id = 102; + list[1].text = "No"; + list[2].id = 103; + list[2].text = "Don't Know"; + + + if (!_gui->message_box(GUI::QUESTION, "My question", list, &response_test)) { + DBG(0, "busy"); + } else { + show_gui(); + } +} + +#endif + +void Application::show_gui() +{ + if (_gui->screen() || !_gui->prepare_dialog()) { + return; + } + + hide_info_layer(); + release_capture(); + _gui->set_screen(_main_screen); + attach_gui_barriers(); +} + +void Application::hide_gui() +{ + if (!_gui->screen()) { + return; + } + + _gui->set_screen(NULL); + detach_gui_barriers(); + show_info_layer(); +} + void Application::do_command(int command) { switch (command) { @@ -650,6 +881,9 @@ void Application::do_command(int command) do_disconnect(); break; #endif + case APP_CMD_SHOW_GUI: + show_gui(); + break; } } @@ -810,7 +1044,7 @@ inline bool Application::is_sticky_trace_key(RedKey key) void Application::reset_sticky() { - _sticky_info.trace_is_on = !_splash_mode && _sys_key_intercept_mode; + _sticky_info.trace_is_on = (_state == VISIBILITY) && _sys_key_intercept_mode; _sticky_info.key_first_down = false; deactivate_interval_timer(*_sticky_info.timer); if (_sticky_info.sticky_mode) { @@ -821,12 +1055,11 @@ void Application::reset_sticky() } _sticky_info.sticky_mode = false; DBG(0, "OFF sticky"); - _gui_layer->set_sticky(false); + _info_layer->set_sticky(false); } _sticky_info.key_down = false; _sticky_info.key = REDKEY_INVALID; - } void Application::on_key_down(RedKey key) @@ -1228,27 +1461,6 @@ void Application::on_display_mode_change() _client.on_display_mode_change(); } -void Application::show_splash(int screen_id) -{ - if (screen_id != 0) { - return; - } - _splash_mode = true; - release_capture(); - ASSERT(!_sticky_info.trace_is_on); - (*_gui_layer).set_splash_mode(); -} - -void Application::hide_splash(int screen_id) -{ - if (screen_id != 0) { - return; - } - _splash_mode = false; - (*_gui_layer).set_info_mode(); - reset_sticky(); -} - uint32_t Application::get_mouse_mode() { return _client.get_mouse_mode(); @@ -1346,17 +1558,62 @@ void Application::send_hotkey_key_set(const HotkeySet& key_set) } } -static inline int str_to_port(const char *str) + +//controller interface begin + +bool Application::connect(const std::string& host, int port, int sport, const std::string& password) { - long port; - char *endptr; - port = strtol(str, &endptr, 0); - if (endptr != str + strlen(str) || port < 0 || port > 0xffff) { - return -1; + if (_state != DISCONNECTED) { + return false; } - return port; + _client.set_target(host, port, sport); + _client.set_password(password); + connect(); + return true; +} + +void Application::disconnect() +{ + do_disconnect(); +} + +void Application::quit() +{ + ProcessLoop::quit(SPICEC_ERROR_CODE_SUCCESS); +} + +void Application::hide_me() +{ + hide_gui(); +} + +bool Application::is_disconnect_allowed() +{ + return _gui_mode == GUI_MODE_FULL; +} + +const std::string& Application::get_host() +{ + return _client.get_host(); } +int Application::get_port() +{ + return _client.get_port(); +} + +int Application::get_sport() +{ + return _client.get_sport(); +} + +const std::string& Application::get_password() +{ + return _client.get_password(); +} + +//controller interface end + bool Application::set_channels_security(CmdLineParser& parser, bool on, char *val) { RedPeer::ConnectionOptions::Type option; @@ -1455,6 +1712,33 @@ bool Application::set_enable_channels(CmdLineParser& parser, bool enable, char * return true; } +void Application::register_channels() +{ + if (_enabled_channels[RED_CHANNEL_DISPLAY]) { + _client.register_channel_factory(DisplayChannel::Factory()); + } + + if (_enabled_channels[RED_CHANNEL_CURSOR]) { + _client.register_channel_factory(CursorChannel::Factory()); + } + + if (_enabled_channels[RED_CHANNEL_INPUTS]) { + _client.register_channel_factory(InputsChannel::Factory()); + } + + if (_enabled_channels[RED_CHANNEL_PLAYBACK]) { + _client.register_channel_factory(PlaybackChannel::Factory()); + } + + if (_enabled_channels[RED_CHANNEL_RECORD]) { + _client.register_channel_factory(RecordChannel::Factory()); + } + + if (_enabled_channels[RED_CHANNEL_TUNNEL]) { + _client.register_channel_factory(TunnelChannel::Factory()); + } +} + bool Application::process_cmd_line(int argc, char** argv) { std::string host; @@ -1477,6 +1761,15 @@ bool Application::process_cmd_line(int argc, char** argv) SPICE_OPT_CANVAS_TYPE, }; + if (argc == 1) { + _gui_mode = GUI_MODE_FULL; + register_channels(); + _main_screen->show(true, NULL); + return true; + } + + _gui_mode = GUI_MODE_ACTIVE_SESSION; + CmdLineParser parser("Spice client", false); parser.add(SPICE_OPT_HOST, "host", "spice server address", "host", true, 'h'); @@ -1504,13 +1797,9 @@ bool Application::process_cmd_line(int argc, char** argv) parser.add(SPICE_OPT_CANVAS_TYPE, "canvas-type", "set rendering canvas", "canvas_type", true); parser.set_multi(SPICE_OPT_CANVAS_TYPE, ','); - _peer_con_opt[RED_CHANNEL_MAIN] = RedPeer::ConnectionOptions::CON_OP_INVALID; - _peer_con_opt[RED_CHANNEL_DISPLAY] = RedPeer::ConnectionOptions::CON_OP_INVALID; - _peer_con_opt[RED_CHANNEL_INPUTS] = RedPeer::ConnectionOptions::CON_OP_INVALID; - _peer_con_opt[RED_CHANNEL_CURSOR] = RedPeer::ConnectionOptions::CON_OP_INVALID; - _peer_con_opt[RED_CHANNEL_PLAYBACK] = RedPeer::ConnectionOptions::CON_OP_INVALID; - _peer_con_opt[RED_CHANNEL_RECORD] = RedPeer::ConnectionOptions::CON_OP_INVALID; - _peer_con_opt[RED_CHANNEL_TUNNEL] = RedPeer::ConnectionOptions::CON_OP_INVALID; + for (int i = RED_CHANNEL_MAIN; i < RED_CHANNEL_END; i++) { + _peer_con_opt[i] = RedPeer::ConnectionOptions::CON_OP_INVALID; + } parser.begin(argc, argv); @@ -1626,31 +1915,11 @@ bool Application::process_cmd_line(int argc, char** argv) return false; } - if (_enabled_channels[RED_CHANNEL_DISPLAY]) { - _client.register_channel_factory(DisplayChannel::Factory()); - } - - if (_enabled_channels[RED_CHANNEL_CURSOR]) { - _client.register_channel_factory(CursorChannel::Factory()); - } - - if (_enabled_channels[RED_CHANNEL_INPUTS]) { - _client.register_channel_factory(InputsChannel::Factory()); - } - - if (_enabled_channels[RED_CHANNEL_PLAYBACK]) { - _client.register_channel_factory(PlaybackChannel::Factory()); - } - - if (_enabled_channels[RED_CHANNEL_RECORD]) { - _client.register_channel_factory(RecordChannel::Factory()); - } - - if (_enabled_channels[RED_CHANNEL_TUNNEL]) { - _client.register_channel_factory(TunnelChannel::Factory()); - } + register_channels(); - _client.init(host.c_str(), port, sport, password.c_str(), auto_display_res); + _client.set_target(host, port, sport); + _client.set_password(password); + _client.set_auto_display_res(auto_display_res); if (full_screen) { enter_full_screen(); diff --git a/client/application.h b/client/application.h index c2b81e6..5c60702 100644 --- a/client/application.h +++ b/client/application.h @@ -30,11 +30,18 @@ class RedScreen; class Application; class ScreenLayer; -class GUILayer; +class InfoLayer; class InputsHandler; class Monitor; class CmdLineParser; class Menu; +class GUI; +class GUITimer; +class GUIBarrier; + +#ifdef GUI_DEMO +class TestTimer; +#endif class ConnectedEvent: public Event { @@ -112,12 +119,28 @@ typedef struct StickyInfo { typedef std::list<KeyHandler*> KeyHandlersStack; +typedef std::list<GUIBarrier*> GUIBarriers; class Application : public ProcessLoop, public Platform::EventListener, public Platform::DisplayModeListner, public CommandTarget { public: + + enum State { + DISCONNECTED, + CONNECTING, + CONNECTED, + VISIBILITY, + DISCONECTING, + }; + + enum GuiMode { + GUI_MODE_FULL, + GUI_MODE_ACTIVE_SESSION, + GUI_MODE_MINIMAL, + }; + Application(); virtual ~Application(); @@ -158,8 +181,6 @@ public: void exit_full_screen(); bool toggle_full_screen(); void minimize(); - void show_splash(int screen_id); - void hide_splash(int screen_id); void set_title(std::wstring& title); void hide(); void show(); @@ -172,12 +193,32 @@ public: Menu* get_app_menu(); virtual void do_command(int command); + + //controller interface begin + bool connect(const std::string& host, int port, int sport, const std::string& password); + void disconnect(); + void quit(); + void hide_me(); + void beep(); + bool is_disconnect_allowed(); + + const std::string& get_host(); + int get_port(); + int get_sport(); + const std::string& get_password(); + //controller interface end + +#ifdef GUI_DEMO + void message_box_test(); +#endif + static int main(int argc, char** argv, const char* version_str); private: bool set_channels_security(CmdLineParser& parser, bool on, char *val); bool set_enable_channels(CmdLineParser& parser, bool enable, char *val); bool set_canvas_option(CmdLineParser& parser, char *val); + void register_channels(); bool process_cmd_line(int argc, char** argv); void abort(); void init_menu(); @@ -185,6 +226,7 @@ private: bool release_capture(); bool do_connect(); bool do_disconnect(); + void set_state(State); void restore_screens_size(); Monitor* find_monitor(int id); @@ -208,6 +250,16 @@ private: void do_on_key_up(RedKey key); void __remove_key_handler(KeyHandler& handler); + void show_info_layer(); + void hide_info_layer(); + void attach_gui_barriers(); + void detach_gui_barriers(); + void show_gui(); + void hide_gui(); + void create_gui_barrier(RedScreen& screen, int id); + void destroyed_gui_barrier(int id); + void destroyed_gui_barriers(); + // returns the press value before operation (i.e., if it was already pressed) bool press_key(RedKey key); bool unpress_key(RedKey key); @@ -238,17 +290,25 @@ private: int _num_keys_pressed; HotKeys _hot_keys; CommandsMap _commands_map; - std::auto_ptr<GUILayer> _gui_layer; + std::auto_ptr<InfoLayer> _info_layer; KeyHandler* _key_handler; KeyHandlersStack _key_handlers; MouseHandler* _mouse_handler; const MonitorsList* _monitors; std::wstring _title; - bool _splash_mode; bool _sys_key_intercept_mode; StickyInfo _sticky_info; std::vector<int> _canvas_types; AutoRef<Menu> _app_menu; + std::auto_ptr<GUI> _gui; + AutoRef<GUITimer> _gui_timer; + GUIBarriers _gui_barriers; + GuiMode _gui_mode; +#ifdef GUI_DEMO + AutoRef<TestTimer> _gui_test_timer; +#endif + + State _state; }; #endif diff --git a/client/gui/gui.cpp b/client/gui/gui.cpp new file mode 100644 index 0000000..1bbf3c4 --- /dev/null +++ b/client/gui/gui.cpp @@ -0,0 +1,1354 @@ +#include "common.h" + +#include <limits.h> +#include <stdlib.h> + +#include "gui.h" +#include "screen.h" +#include "utils.h" +#include "debug.h" +#include "red_pixmap_cairo.h" +#include "resource_provider.h" + +#include "CEGUISystem.h" +#include "CEGUIWindowManager.h" +#include "CEGUIWindow.h" +#include "CEGUIFontManager.h" +#include "CEGUIExceptions.h" +#include "CEGUIScheme.h" +#include "elements/CEGUIPushButton.h" +#include "elements/CEGUIEditbox.h" +#include "elements/CEGUITabControl.h" +#include "elements/CEGUIListbox.h" +#include "elements/CEGUIListboxTextItem.h" + +#define MAIN_GUI_WIDTH 640 +#define MAIN_GUI_HEIGHT 480 +#define BUTTON_WIDTH 90 +#define BUTTON_HEIGHT 22 +#define GUI_SPACE 10 +#define GUI_LABEL_WIDTH 65 +#define GUI_LABEL_HEIGHT 22 +#define GUI_PORT_WIDTH 50 +#define GUI_TEXT_BOX_HEIGHT GUI_LABEL_HEIGHT + +#define LOGIN_DIALOG_WIDTH 400 +#define LOGIN_DIALOG_HEIGHT 300 +#define LOGIN_DIALOG_V_START 150 + +#define CONNECTING_DIALOG_WIDTH 400 +#define CONNECTING_DIALOG_HEIGHT 300 + +#define MESSAGE_BOX_WIDTH 380 +#define MESSAGE_BOX_HEIGHT 150 + +#define CONNECT_OPTION_DIALOG_WIDTH LOGIN_DIALOG_WIDTH +#define CONNECT_OPTION_DIALOG_HEIGHT LOGIN_DIALOG_HEIGHT + +static inline void set_win_pos(CEGUI::Window* win, int x, int y) +{ + win->setPosition(CEGUI::UVector2(cegui_absdim((float)x), cegui_absdim((float)y))); +} + +static inline void set_win_size(CEGUI::Window* win, int width, int height) +{ + win->setSize(CEGUI::UVector2(cegui_absdim((float)width), cegui_absdim((float)height))); +} + +static void add_bottom_button(CEGUI::Window* parent, const char *str, + CEGUI::SubscriberSlot subscriber, + int& position) +{ + CEGUI::Window* button = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/Button"); + int win_width = (int)parent->getWidth().asAbsolute(1); + int win_height = (int)parent->getHeight().asAbsolute(1); + int y_pos = win_height - BUTTON_HEIGHT - GUI_SPACE; + + position += BUTTON_WIDTH + GUI_SPACE; + set_win_pos(button, win_width - position, y_pos); + set_win_size(button, BUTTON_WIDTH, BUTTON_HEIGHT); + button->setText(str); + button->subscribeEvent(CEGUI::PushButton::EventClicked, subscriber); + button->setInheritsAlpha(false); + //button->setTooltipText("tool tip"); + parent->addChildWindow(button); +} + +#ifdef GUI_DEMO + +class SampleTabFactory: public GUI::TabFactory { +public: + + class MyListItem : public CEGUI::ListboxTextItem { + public: + MyListItem (const CEGUI::String& text) + : CEGUI::ListboxTextItem(text) + { + setSelectionBrushImage("TaharezLook", "MultiListSelectionBrush"); + } + }; + + class SampleTab: public GUI::Tab { + public: + SampleTab(int id, int width, int height) + { + string_printf(_name, "SampleTab-%d", id); + CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton(); + _root_window = winMgr.createWindow("TaharezLook/StaticText"); + set_win_pos(_root_window, 0, 0); + set_win_size(_root_window, width, height); + _root_window->setText("Tab of SampleTabFactory"); + + if (id != 1) { + return; + } + + _list = (CEGUI::Listbox*)winMgr.createWindow("TaharezLook/Listbox"); + set_win_pos(_list, 10, 10); + set_win_size(_list, 200, 100); + _list->setMultiselectEnabled(false); + _list->addItem(new MyListItem("Item-1")); + _list->addItem(new MyListItem("Item-2")); + _list->addItem(new MyListItem("Item-3")); + _list->addItem(new MyListItem("Item-4")); + _list->addItem(new MyListItem("Item-5")); + _list->addItem(new MyListItem("Item-6")); + + _list->subscribeEvent(CEGUI::Listbox::EventSelectionChanged, + CEGUI::Event::Subscriber(&SampleTab::handle_list_selection, + this)); + + _root_window->addChildWindow(_list); + + _label = winMgr.createWindow("TaharezLook/StaticText"); + set_win_pos(_label, 220, 10); + set_win_size(_label, 200, 22); + _root_window->addChildWindow(_label); + + _list->setItemSelectState((size_t)0, true); + + } + + virtual ~SampleTab() + { + CEGUI::WindowManager::getSingleton().destroyWindow(_root_window); + } + + virtual CEGUI::Window& get_root_window() + { + return *_root_window; + } + + virtual const std::string& get_name() + { + return _name; + } + + bool handle_list_selection(const CEGUI::EventArgs& e) + { + DBG(0, "changed"); + CEGUI::ListboxItem* selection = _list->getFirstSelectedItem(); + if (selection) { + _label->setText(selection->getText()); + return true; + } + + if (_list->getItemCount()) { + _list->setItemSelectState((size_t)_list->getItemCount() - 1, true); + } + + return true; + } + + private: + std::string _name; + CEGUI::Window* _root_window; + CEGUI::Listbox* _list; + CEGUI::Window* _label; + }; + + SampleTabFactory(int id) + : GUI::TabFactory(id) + , _id (id) + { + } + + GUI::Tab* create_tab(bool connected, int width, int height) + { + if (!connected && _id % 2 == 0) { + return NULL; + } + return new SampleTab(_id, width, height); + } + +private: + int _id; +}; + +#endif + +class GUI::Dialog { +public: + Dialog(GUI& gui, bool close_on_message_click = false) + : _gui (gui) + , _root (NULL) + , _message_box (NULL) + , _box_response (NULL) + , _close_on_message_click (close_on_message_click) + { + } + + virtual ~Dialog() + { + if (gui_system().getGUISheet() == _root) { + gui_system().setGUISheet(NULL); + } + + CEGUI::WindowManager::getSingleton().destroyWindow(_root); + } + + CEGUI::Window& root_window() { return *_root;} + Application& application() { return _gui.get_application();} + CEGUI::System& gui_system() { return _gui.gui_system();} + + void set_dialog(Dialog* dialog) { _gui.set_dialog(dialog);} + TabFactorys& get_factoris() { return _gui._tab_factorys;} + + bool message_box(MessageType type, const char *text, const ButtonsList& buttons, + BoxResponse* response_handler); + void error_box(const char* error_message); + + void pre_destroy(); + +private: + void handle_message_click(int id); + void set_opaque(CEGUI::Window* win); + + void dim(); + void undim(); + +protected: + GUI& _gui; + CEGUI::Window* _root; + +private: + class BottonAction { + public: + BottonAction(Dialog& dialog, int id) + : _dialog (dialog) + , _id (id) + { + } + + bool operator () (const CEGUI::EventArgs& e) + { + _dialog.handle_message_click(_id); + return true; + } + + private: + Dialog& _dialog; + int _id; + }; + + CEGUI::Window* _message_box; + BoxResponse* _box_response; + + class UndimInfo { + public: + UndimInfo(const CEGUI::String& name, float alpha, bool inherits) + : _name (name) + , _alpha (alpha) + , _inherits (inherits) + { + } + + void restore() + { + try { + CEGUI::Window* win = CEGUI::WindowManager::getSingleton().getWindow(_name); + win->setAlpha(_alpha); + win->setInheritsAlpha(_inherits); + } catch (...) { + } + } + + private: + CEGUI::String _name; + float _alpha; + bool _inherits; + + }; + + std::list<UndimInfo*> _undim_info_list; + bool _close_on_message_click; +}; + + +void GUI::Dialog::set_opaque(CEGUI::Window* win) +{ + float alpha = win->getAlpha(); + bool inherits = win->inheritsAlpha(); + + if (alpha != 1 || !inherits ) { + _undim_info_list.push_back(new UndimInfo(win->getName(), alpha, inherits)); + win->setInheritsAlpha(true); + win->setAlpha(1); + } + + size_t child_count = win->getChildCount(); + for (size_t i = 0; i < child_count; ++i) { + CEGUI::Window* child = win->getChildAtIdx(i); + set_opaque(child); + } +} + +void GUI::Dialog::dim() +{ + set_opaque(_root); + _root->setAlpha(0.5); +} + +void GUI::Dialog::undim() +{ + while (!_undim_info_list.empty()) { + UndimInfo* inf = _undim_info_list.front(); + _undim_info_list.pop_front(); + inf->restore(); + delete inf; + } + _root->setAlpha(1); +} + +bool GUI::Dialog::message_box(MessageType type, const char *text, const ButtonsList& buttons, + BoxResponse* response_handler) +{ + if (_message_box) { + return false; + } + + try { + CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton(); + + CEGUI::Window* wnd = _message_box = winMgr.createWindow("TaharezLook/StaticText"); + int x_pos = (MAIN_GUI_WIDTH - MESSAGE_BOX_WIDTH) / 2; + int y_pos = (MAIN_GUI_HEIGHT - MESSAGE_BOX_HEIGHT) / 3; + set_win_pos(wnd, x_pos, y_pos); + set_win_size(wnd, MESSAGE_BOX_WIDTH, MESSAGE_BOX_HEIGHT); + wnd->setModalState(true); + wnd->setInheritsAlpha(false); + dim(); + _root->addChildWindow(wnd); + + CEGUI::Window* text_wnd = winMgr.createWindow("TaharezLook/StaticText"); + set_win_pos(text_wnd, GUI_SPACE, GUI_SPACE); + set_win_size(text_wnd, MESSAGE_BOX_WIDTH - 2 * GUI_SPACE, + MESSAGE_BOX_HEIGHT - 3 * GUI_SPACE - BUTTON_HEIGHT); + text_wnd->setProperty("FrameEnabled", "false"); + text_wnd->setProperty("HorzFormatting", "WordWrapLeftAligned"); + text_wnd->setProperty("VertFormatting", "TopAligned"); + text_wnd->setText(text); + //text_wnd->getTextRenderArea(); + wnd->addChildWindow(text_wnd); + + x_pos = 0; + + for (unsigned int i = 0; i < buttons.size(); i++) { + add_bottom_button(wnd, buttons[i].text, + CEGUI::Event::Subscriber(BottonAction(*this, buttons[i].id)), + x_pos); + } + + _box_response = response_handler; + } catch (CEGUI::Exception& e) { + LOG_ERROR("Exception: %s", e.getMessage().c_str()); + throw; + } + + return true; +} + +class BoxResponseEvent: public Event { +public: + BoxResponseEvent(GUI::BoxResponse* box_response, int id) + : _box_response (box_response) + , _id (id) + { + } + + virtual void response(AbstractProcessLoop &events_loop) + { + _box_response->response(_id); + } + +private: + GUI::BoxResponse* _box_response; + int _id; +}; + +class BoxAbortEvent: public Event { +public: + BoxAbortEvent(GUI::BoxResponse* box_response) + : _box_response (box_response) + { + } + + virtual void response(AbstractProcessLoop &events_loop) + { + _box_response->aborted(); + } + +private: + GUI::BoxResponse* _box_response; +}; + +void GUI::Dialog::handle_message_click(int id) +{ + DBG(0, ""); + ASSERT(_message_box); + _message_box->setModalState(false); + _root->removeChildWindow(_message_box); + CEGUI::Window *win = _message_box; + _message_box = NULL; + CEGUI::WindowManager::getSingleton().destroyWindow(win); + undim(); + if (_box_response) { + AutoRef<BoxResponseEvent> event(new BoxResponseEvent(_box_response, id)); + _box_response = NULL; + application().push_event(*event); + } + + if (_close_on_message_click) { + application().hide_me(); + } +} + +void GUI::Dialog::pre_destroy() + { + if (_box_response) { + AutoRef<BoxAbortEvent> event(new BoxAbortEvent(_box_response)); + _box_response = NULL; + application().push_event(*event); + } +} + +void GUI::Dialog::error_box(const char* message) +{ + ASSERT(message && strlen(message) > 0); + DBG(0, "%s", message); + ButtonsList list(1); + list[0].id = 0; + list[0].text = res_get_string(STR_BUTTON_OK); + message_box(INFO, message, list, NULL); +} + +class TabDialog : public GUI::Dialog { +public: + TabDialog(GUI& gui, bool connected); + virtual ~TabDialog(); + +protected: + CEGUI::Window* _main_win; + +private: + typedef std::list<GUI::Tab*> Tabs; + Tabs _tabs; +}; + +class MessageDialog : public GUI::Dialog { +public: + MessageDialog(GUI& gui); + virtual ~MessageDialog() {} +}; + +class LoginDialog : public GUI::Dialog { +public: + LoginDialog(GUI& guip); + + bool handle_connect(const CEGUI::EventArgs& e); + bool handle_quit(const CEGUI::EventArgs& e); + bool handle_options(const CEGUI::EventArgs& e); + +private: + static void set_port_text(CEGUI::Window* win, int port); + +private: + CEGUI::Window* _host_box; + CEGUI::Window* _port_box; + CEGUI::Window* _sport_box; + CEGUI::Window* _pass_box; +}; + +class PreLoginDialog: public TabDialog { +public: + PreLoginDialog(GUI& gui); + + bool handle_back(const CEGUI::EventArgs& e); + bool handle_quit(const CEGUI::EventArgs& e); +}; + +PreLoginDialog::PreLoginDialog(GUI& gui) + : TabDialog(gui, false) +{ + try { + + int position = 0; + add_bottom_button(_main_win, res_get_string(STR_BUTTON_BACK), + CEGUI::Event::Subscriber(&PreLoginDialog::handle_back, this), + position); + add_bottom_button(_main_win, res_get_string(STR_BUTTON_QUIT), + CEGUI::Event::Subscriber(&PreLoginDialog::handle_quit, this), + position); + + } catch (CEGUI::Exception& e) { + LOG_ERROR("Exception: %s", e.getMessage().c_str()); + } catch (...) { + throw; + } +} + +bool PreLoginDialog::handle_back(const CEGUI::EventArgs& e) +{ + set_dialog(new LoginDialog(_gui)); + return true; +} + +bool PreLoginDialog::handle_quit(const CEGUI::EventArgs& e) +{ + DBG(0, ""); + application().quit(); + return true; +} + +MessageDialog::MessageDialog(GUI& gui) + : GUI::Dialog(gui, true) +{ + try { + CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton(); + _root = winMgr.createWindow("DefaultWindow"); + set_win_size(_root, MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT); + } catch (CEGUI::Exception& e) { + LOG_ERROR("Exception: %s", e.getMessage().c_str()); + throw; + } +} + +LoginDialog::LoginDialog(GUI& gui) + : GUI::Dialog(gui) +{ + try { + CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton(); + _root = winMgr.createWindow("DefaultWindow"); + + CEGUI::Window* wnd = winMgr.createWindow("TaharezLook/StaticText"); + int x_pos = (MAIN_GUI_WIDTH - LOGIN_DIALOG_WIDTH) / 2; + int y_pos = (MAIN_GUI_HEIGHT - LOGIN_DIALOG_HEIGHT) / 3; + set_win_pos(wnd, x_pos, y_pos); + set_win_size(wnd, LOGIN_DIALOG_WIDTH, LOGIN_DIALOG_HEIGHT); + _root->addChildWindow(wnd); + + CEGUI::Window* host_label = winMgr.createWindow("TaharezLook/StaticText"); + host_label->setText(res_get_string(STR_LABEL_HOST)); + host_label->setProperty("FrameEnabled", "false"); + host_label->setProperty("BackgroundEnabled", "false"); + set_win_pos(host_label, GUI_SPACE, LOGIN_DIALOG_V_START); + set_win_size(host_label, GUI_LABEL_WIDTH, GUI_LABEL_HEIGHT); + + wnd->addChildWindow(host_label); + + _host_box = winMgr.createWindow("TaharezLook/Editbox"); + set_win_pos(_host_box, GUI_LABEL_WIDTH + GUI_SPACE, LOGIN_DIALOG_V_START); + int width = LOGIN_DIALOG_WIDTH - GUI_LABEL_WIDTH - 2 * GUI_SPACE; + set_win_size(_host_box, width, GUI_LABEL_HEIGHT); + _host_box->setText(application().get_host()); + wnd->addChildWindow(_host_box); + + CEGUI::Window* port_label = winMgr.createWindow("TaharezLook/StaticText"); + port_label->setText(res_get_string(STR_LABEL_PORT)); + port_label->setProperty("FrameEnabled", "false"); + port_label->setProperty("BackgroundEnabled", "false"); + y_pos = LOGIN_DIALOG_V_START + GUI_LABEL_HEIGHT + GUI_SPACE; + set_win_pos(port_label, GUI_SPACE, y_pos); + set_win_size(port_label, GUI_LABEL_WIDTH, GUI_LABEL_HEIGHT); + wnd->addChildWindow(port_label); + + _port_box = winMgr.createWindow("TaharezLook/Editbox"); + set_win_pos(_port_box, GUI_SPACE + GUI_LABEL_WIDTH, y_pos); + set_win_size(_port_box, GUI_PORT_WIDTH, GUI_TEXT_BOX_HEIGHT); + set_port_text(_port_box, application().get_port()); + wnd->addChildWindow(_port_box); + + _sport_box = winMgr.createWindow("TaharezLook/Editbox"); + x_pos = LOGIN_DIALOG_WIDTH - GUI_SPACE - GUI_PORT_WIDTH; + set_win_pos(_sport_box, x_pos, y_pos); + set_win_size(_sport_box, GUI_PORT_WIDTH, GUI_TEXT_BOX_HEIGHT); + set_port_text(_sport_box, application().get_sport()); + wnd->addChildWindow(_sport_box); + + CEGUI::Window* sport_label = winMgr.createWindow("TaharezLook/StaticText"); + sport_label->setText(res_get_string(STR_LABEL_SPORT)); + sport_label->setProperty("FrameEnabled", "false"); + sport_label->setProperty("BackgroundEnabled", "false"); + x_pos -= GUI_LABEL_WIDTH; + set_win_pos(sport_label, x_pos, y_pos); + set_win_size(sport_label, GUI_LABEL_WIDTH, GUI_LABEL_HEIGHT); + wnd->addChildWindow(sport_label); + + CEGUI::Window* label = winMgr.createWindow("TaharezLook/StaticText"); + label->setText(res_get_string(STR_LABEL_PASSWORD)); + label->setProperty("FrameEnabled", "false"); + label->setProperty("BackgroundEnabled", "false"); + y_pos += GUI_LABEL_HEIGHT + GUI_SPACE; + set_win_pos(label, GUI_SPACE, y_pos); + set_win_size(label, GUI_LABEL_WIDTH, GUI_LABEL_HEIGHT); + wnd->addChildWindow(label); + + _pass_box = winMgr.createWindow("TaharezLook/Editbox"); + x_pos = GUI_LABEL_WIDTH + GUI_SPACE; + set_win_pos(_pass_box, x_pos, y_pos); + width = LOGIN_DIALOG_WIDTH - GUI_LABEL_WIDTH - 2 * GUI_SPACE; + set_win_size(_pass_box, width, GUI_TEXT_BOX_HEIGHT); + ((CEGUI::Editbox*)_pass_box)->setTextMasked(true); + ((CEGUI::Editbox*)_pass_box)->setMaskCodePoint(/*0x000026AB*/ 0x00002022 ); + _pass_box->setText(application().get_password().c_str()); + wnd->addChildWindow(_pass_box); + + x_pos = 0; + add_bottom_button(wnd, + res_get_string(STR_BUTTON_CONNECT), + CEGUI::Event::Subscriber(&LoginDialog::handle_connect, this), + x_pos); + add_bottom_button(wnd, + res_get_string(STR_BUTTON_QUIT), + CEGUI::Event::Subscriber(&LoginDialog::handle_quit, this), + x_pos); + add_bottom_button(wnd, + res_get_string(STR_BUTTON_OPTIONS), + CEGUI::Event::Subscriber(&LoginDialog::handle_options, this), + x_pos); + + } catch (CEGUI::Exception& e) { + LOG_ERROR("Exception: %s", e.getMessage().c_str()); + throw; + } +} + +bool LoginDialog::handle_connect(const CEGUI::EventArgs& e) +{ + const char* host_name = _host_box->getText().c_str(); + + if (strlen(host_name) == 0) { + error_box(res_get_string(STR_MESG_MISSING_HOST_NAME)); + return true; + } + int port = -1; + int sport = -1; + + const char* port_str = _port_box->getText().c_str(); + if (strlen(port_str) != 0 && (port = str_to_port(port_str)) == -1) { + error_box(res_get_string(STR_MESG_INVALID_PORT)); + return true; + } + + const char* sport_str = _sport_box->getText().c_str(); + if (strlen(sport_str) != 0 && (sport = str_to_port(sport_str)) == -1) { + error_box(res_get_string(STR_MESG_INVALID_SPORT)); + return true; + } + + if (port == sport && port == -1) { + error_box(res_get_string(STR_MESG_MISSING_PORT)); + return true; + } + + DBG(0, "host %s port %d sport %d", host_name, port, sport); + application().connect(host_name, port, sport, _pass_box->getText().c_str()); + return true; +} + +bool LoginDialog::handle_quit(const CEGUI::EventArgs& e) +{ + DBG(0, ""); + application().quit(); + return true; +} + +bool LoginDialog::handle_options(const CEGUI::EventArgs& e) +{ + set_dialog(new PreLoginDialog(_gui)); + return true; +} + +void LoginDialog::set_port_text(CEGUI::Window* win, int port) +{ + if (port == -1) { + win->setText(""); + return; + } + + char port_string[25]; + sprintf(port_string, "%d", port); + win->setText(port_string); +} + +class ConnectingDialog : public GUI::Dialog { +public: + ConnectingDialog(GUI& gui); + +private: + bool handle_cancel(const CEGUI::EventArgs& e); + bool handle_quit(const CEGUI::EventArgs& e); +}; + +bool ConnectingDialog::handle_cancel(const CEGUI::EventArgs& e) +{ + DBG(0, ""); + application().disconnect(); + return true; +} + +bool ConnectingDialog::handle_quit(const CEGUI::EventArgs& e) +{ + DBG(0, ""); + application().quit(); + return true; +} + +ConnectingDialog::ConnectingDialog(GUI& gui) + : GUI::Dialog(gui) +{ + try { + CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton(); + _root = winMgr.createWindow("DefaultWindow"); + + CEGUI::Window* wnd = winMgr.createWindow("TaharezLook/StaticText"); + int x_pos = (MAIN_GUI_WIDTH - CONNECTING_DIALOG_WIDTH) / 2; + int y_pos = (MAIN_GUI_HEIGHT - CONNECTING_DIALOG_HEIGHT) / 2; + set_win_pos(wnd, x_pos, y_pos); + set_win_size(wnd, CONNECTING_DIALOG_WIDTH, CONNECTING_DIALOG_HEIGHT); + CEGUI::String text(res_get_string(STR_MESG_CONNECTING)); + wnd->setText(text + " " + application().get_host()); + wnd->setProperty("HorzFormatting", "LeftAligned"); + wnd->setProperty("VertFormatting", "TopAligned"); + _root->addChildWindow(wnd); + + x_pos = 0; + + add_bottom_button(wnd, res_get_string(STR_BUTTON_CANCEL), + CEGUI::Event::Subscriber(&ConnectingDialog::handle_cancel, this), + x_pos); + + if (_gui.is_disconnect_allowed()) { + add_bottom_button(wnd, res_get_string(STR_BUTTON_QUIT), + CEGUI::Event::Subscriber(&ConnectingDialog::handle_quit, this), + x_pos); + } + + } catch (CEGUI::Exception& e) { + LOG_ERROR("Exception: %s", e.getMessage().c_str()); + throw; + } +} + +TabDialog::TabDialog(GUI& gui, bool connected) + : GUI::Dialog(gui) +{ + CEGUI::WindowManager& winMgr = CEGUI::WindowManager::getSingleton(); + + try { + _root = winMgr.createWindow("DefaultWindow"); + + CEGUI::Window* wnd = _main_win = winMgr.createWindow("TaharezLook/StaticText"); + set_win_pos(wnd, 0, 0); + set_win_size(wnd, MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT); + wnd->setAlpha(0.5); + _root->addChildWindow(wnd); + + CEGUI::TabControl* tab_ctrl; + tab_ctrl = static_cast<CEGUI::TabControl*>(winMgr.createWindow("TaharezLook/TabControl")); + set_win_pos(tab_ctrl, GUI_SPACE, GUI_SPACE); + int tab_width = MAIN_GUI_WIDTH - GUI_SPACE * 2; + int tab_height = MAIN_GUI_HEIGHT - GUI_SPACE * 3 - BUTTON_HEIGHT; + set_win_size(tab_ctrl, tab_width, tab_height); + tab_ctrl->setInheritsAlpha(false); + tab_ctrl->setTabHeight(cegui_absdim(22)); + tab_ctrl->setTabTextPadding(cegui_absdim(10)); + tab_height = (int)tab_ctrl->getTabHeight().asAbsolute(1); + wnd->addChildWindow(tab_ctrl); + + GUI::TabFactorys& _tab_factorys = get_factoris(); + GUI::TabFactorys::iterator iter = _tab_factorys.begin(); + + int tab_content_width = MAIN_GUI_WIDTH - GUI_SPACE * 4; + int tab_content_height = MAIN_GUI_HEIGHT - GUI_SPACE * 5 - BUTTON_HEIGHT - tab_height; + + for (; iter != _tab_factorys.end(); iter++) { + + GUI::Tab* tab = (*iter)->create_tab(connected, tab_content_width, + tab_content_height); + + if (!tab) { + continue; + } + + _tabs.push_front(tab); + CEGUI::Window* gui_sheet = winMgr.createWindow("DefaultGUISheet"); + gui_sheet->setText(tab->get_name()); + set_win_pos(gui_sheet, GUI_SPACE, GUI_SPACE); + set_win_size(gui_sheet, tab_content_width, tab_content_height); + tab_ctrl->addTab(gui_sheet); + CEGUI::Window& tab_window = tab->get_root_window(); + tab_window.setDestroyedByParent(false); + gui_sheet->addChildWindow(&tab_window); + } + + } catch (CEGUI::Exception& e) { + LOG_ERROR("Exception: %s", e.getMessage().c_str()); + } catch (...) { + throw; + } +} + +TabDialog::~TabDialog() +{ + while (!_tabs.empty()) { + GUI::Tab* tab = *_tabs.begin(); + _tabs.pop_front(); + delete tab; + } +} + +class SettingsDialog : public TabDialog { +public: + SettingsDialog(GUI& gui); + + bool handle_close(const CEGUI::EventArgs& e); + bool handle_quit(const CEGUI::EventArgs& e); + bool handle_disconnect(const CEGUI::EventArgs& e); +}; + +bool SettingsDialog::handle_close(const CEGUI::EventArgs& e) +{ + DBG(0, ""); + application().hide_me(); + return true; +} + +bool SettingsDialog::handle_quit(const CEGUI::EventArgs& e) +{ + DBG(0, ""); + application().quit(); + return true; +} + +bool SettingsDialog::handle_disconnect(const CEGUI::EventArgs& e) +{ + DBG(0, ""); + application().disconnect(); + return true; +} + +SettingsDialog::SettingsDialog(GUI& gui) + : TabDialog(gui, true) +{ + try { + + int position = 0; + add_bottom_button(_main_win, res_get_string(STR_BUTTON_CLOSE), + CEGUI::Event::Subscriber(&SettingsDialog::handle_close, this), + position); + add_bottom_button(_main_win, res_get_string(STR_BUTTON_QUIT), + CEGUI::Event::Subscriber(&SettingsDialog::handle_quit, this), + position); + + if (_gui.is_disconnect_allowed()) { + add_bottom_button(_main_win, res_get_string(STR_BUTTON_DISCONNECT), + CEGUI::Event::Subscriber(&SettingsDialog::handle_disconnect, this), + position); + } + + } catch (CEGUI::Exception& e) { + LOG_ERROR("Exception: %s", e.getMessage().c_str()); + } catch (...) { + throw; + } +} + +GUI::GUI(Application& app, Application::State state) + : ScreenLayer (SCREEN_LAYER_GUI, false) + , _app (app) + , _state (state) + , _pixmap (new RedPixmapCairo(MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, RedPixmap::RGB32, true, NULL, + NULL)) + , _renderer (new CEGUI::SoftRenderer(_pixmap->get_data(), MAIN_GUI_WIDTH, MAIN_GUI_HEIGHT, + _pixmap->get_stride())) + , _gui_system (new CEGUI::System(_renderer, new CEGUIResourceProvider())) + , _dialog (NULL) + , _prev_time (Platform::get_monolithic_time()) + +{ + LOG_INFO(""); + init_cegui(); +#ifdef GUI_DEMO + register_tab_factory(*(new SampleTabFactory(2))); + register_tab_factory(*(new SampleTabFactory(3))); + register_tab_factory(*(new SampleTabFactory(1))); + register_tab_factory(*(new SampleTabFactory(4))); + register_tab_factory(*(new SampleTabFactory(5))); +#endif + create_dialog(); +} + +GUI::~GUI() +{ + delete _dialog; + detach(); + delete _gui_system; + delete _renderer; + delete _pixmap; +} + +void GUI::init_cegui() +{ + CEGUI::SchemeManager::getSingleton().loadScheme("TaharezLook.scheme"); + _gui_system->setDefaultMouseCursor("TaharezLook", "MouseArrow"); + _gui_system->setDefaultTooltip("TaharezLook/Tooltip"); + + CEGUI::String font_name("DejaVuSans-10"); + CEGUI::Font* font; + + if (!CEGUI::FontManager::getSingleton().isFontPresent(font_name)) { + font = CEGUI::FontManager::getSingleton().createFont(font_name + ".font"); + } else { + font = CEGUI::FontManager::getSingleton().getFont(font_name); + } + + //font->setProperty("PointSize", "10"); + CEGUI::System::getSingleton().setDefaultFont(font); +} + +bool comp_factorys(GUI::TabFactory* f1, GUI::TabFactory* f2) +{ + return f1->get_order() < f2->get_order(); +} + +void GUI::register_tab_factory(TabFactory& factory) +{ + TabFactorys::iterator iter = _tab_factorys.begin(); + + for (; iter != _tab_factorys.end(); iter++) { + if ((*iter) == &factory) { + return; + } + } + + _tab_factorys.push_back(&factory); + _tab_factorys.sort(comp_factorys); +} + +void GUI::unregister_tab_factory(TabFactory& factory) +{ + TabFactorys::iterator iter = _tab_factorys.begin(); + + for (; iter != _tab_factorys.end(); iter++) { + if ((*iter) == &factory) { + _tab_factorys.erase(iter); + return; + } + } +} + +void GUI::detach() +{ + if (!screen()) { + return; + } + clear_area(); + screen()->detach_layer(*this); + set_dialog(NULL); +} + +void GUI::conditional_update() +{ + if (_gui_system->isRedrawRequested()) { + invalidate(); + } +} + +void GUI::update_layer_area() +{ + if (!_dialog || !screen()) { + clear_area(); + return; + } + Point screen_size = screen()->get_size(); + + int dx = (screen_size.x - MAIN_GUI_WIDTH) / 2; + int dy = (screen_size.y - MAIN_GUI_HEIGHT) / 2; + + DBG(0, "screen_size.x = %d screen_size.y = %d", screen_size.x, screen_size.y); + + _pixmap->set_origin(-dx, -dy); + CEGUI::Window& root = _dialog->root_window(); + QRegion regin; + region_init(®in); + + for (unsigned int i = 0; i < root.getChildCount(); i++) { + + CEGUI::Window* child = root.getChildAtIdx(i); + if (!child->isVisible()) { + continue; + } + + CEGUI::Rect area = child->getPixelRect(); + Rect r; + r.left = (int)area.d_left + dx; + r.right = (int)area.d_right + dx; + r.top = (int)area.d_top + dy; + r.bottom = (int)area.d_bottom + dy; + region_add(®in, &r); + + } + set_area(regin); + region_destroy(®in); +} + +void GUI::copy_pixels(const QRegion& dest_region, RedDrawable& dest) +{ + if (region_is_empty(&dest_region)) { + return; + } + + for (int i = 0; i < (int)dest_region.num_rects; i++) { + Rect* r = &dest_region.rects[i]; + _pixmap->copy_pixels(dest, r->left, r->top, *r); + } + + _gui_system->renderGUI(); + for (int i = 0; i < (int)dest_region.num_rects; i++) { + Rect* r = &dest_region.rects[i]; + dest.copy_pixels(*_pixmap, r->left, r->top, *r); + } +} + +void GUI::on_size_changed() +{ + DBG(0, ""); + update_layer_area(); +} + +void GUI::set_dialog(Dialog* dialog) +{ + if (_dialog) { + _dialog->pre_destroy(); + delete _dialog; + _dialog = NULL; + } + + if (!dialog) { + return; + } + + _dialog = dialog; + gui_system().setGUISheet(&_dialog->root_window()); + update_layer_area(); +} + +void GUI::create_dialog() +{ + switch (_state) { + case Application::DISCONNECTED: + set_dialog(new LoginDialog(*this)); + break; + case Application::VISIBILITY: + set_dialog(new SettingsDialog(*this)); + break; + case Application::CONNECTING: + set_dialog(new ConnectingDialog(*this)); + break; + case Application::CONNECTED: + break; + case Application::DISCONECTING: + set_dialog(NULL); + break; + } +} + +void GUI::set_state(Application::State state) +{ + if (_state == state) { + return; + } + _state = state; + create_dialog(); +} + +bool GUI::prepare_dialog() +{ + if (!_dialog) { + create_dialog(); + } + + return !!_dialog; +} + +void GUI::set_screen(RedScreen* in_screen) +{ + detach(); + if (!in_screen) { + _app.remove_key_handler(*this); + return; + } + ASSERT(!screen()); + in_screen->attach_layer(*this); + CEGUI::MouseCursor::getSingleton().hide(); + update_layer_area(); + _app.set_key_handler(*this); +} + +void GUI::on_pointer_enter(int x, int y, unsigned int buttons_state) +{ + CEGUI::MouseCursor::getSingleton().show(); + screen()->hide_cursor(); + _app.set_key_handler(*this); + on_pointer_motion(x, y, buttons_state); +} + +void GUI::on_pointer_motion(int x, int y, unsigned int buttons_state) +{ + _gui_system->injectMousePosition(float(x + _pixmap->get_origin().x), + float(y + _pixmap->get_origin().y)); + invalidate(); +} + +void GUI::on_mouse_button_press(int button, int buttons_state) +{ + _app.set_key_handler(*this); + switch (button) { + case REDC_MOUSE_LBUTTON: + _gui_system->injectMouseButtonDown(CEGUI::LeftButton); + break; + case REDC_MOUSE_MBUTTON: + _gui_system->injectMouseButtonDown(CEGUI::MiddleButton); + break; + case REDC_MOUSE_RBUTTON: + _gui_system->injectMouseButtonDown(CEGUI::RightButton); + break; + case REDC_MOUSE_UBUTTON: + _gui_system->injectMouseWheelChange(-1); + break; + case REDC_MOUSE_DBUTTON: + _gui_system->injectMouseWheelChange(1); + break; + default: + THROW("invalid RedButton %d", button); + } + conditional_update(); +} + +void GUI::on_mouse_button_release(int button, int buttons_state) +{ + switch (button) { + case REDC_MOUSE_LBUTTON: + _gui_system->injectMouseButtonUp(CEGUI::LeftButton); + brea... [truncated message content] |
From: Yaniv K. <yk...@re...> - 2009-12-28 10:37:12
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit ce480b07335d8f7d380ac302a1a6422c4fa3742b Author: Yaniv Kamay <yk...@re...> Date: Mon Dec 28 00:31:35 2009 +0200 client: add soft renderer and cegui diff --git a/client/gui/softrenderer.cpp b/client/gui/softrenderer.cpp new file mode 100644 index 0000000..9e08f7a --- /dev/null +++ b/client/gui/softrenderer.cpp @@ -0,0 +1,372 @@ +#include "common.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "utils.h" +#include "debug.h" + +#include "softrenderer.h" +#include "softtexture.h" + +#include "CEGUIExceptions.h" +#include "CEGUIImageCodec.h" +#include "CEGUIDynamicModule.h" +#include "CEGUIEventArgs.h" + +#define S_(X) #X +#define STRINGIZE(X) S_(X) + +namespace CEGUI { + +SoftRenderer::SoftRenderer(uint8_t* surface, uint width, uint height, uint stride, + ImageCodec* codec) + : _surface (surface) + , _width (width) + , _height (height) + , _image_codec (codec) + , _image_codec_module (NULL) + , _queueing(true) +{ + assert(stride == _width * 4); //for now + if (!_image_codec) { + setupImageCodec(); + } +} + +SoftRenderer::~SoftRenderer() +{ + destroyAllTextures(); + cleanupImageCodec(); +} + + +void SoftRenderer::reset_surface(uint8_t* surface, uint width, uint height, uint stride) +{ + assert(stride == width * 4); //for now + _surface = surface; + _width = width; + _height = height; + + EventArgs args; + fireEvent(EventDisplaySizeChanged, args, EventNamespace); +} + +#if defined(CEGUI_STATIC) +extern "C" CEGUI::ImageCodec* createImageCodec(void); +extern "C" void destroyImageCodec(CEGUI::ImageCodec*); +#endif + +void SoftRenderer::setupImageCodec() +{ +#if defined(CEGUI_STATIC) + _destroy_image_codec = destroyImageCodec; + _image_codec = createImageCodec(); +#else + String _default_codec_name(STRINGIZE(TGAImageCodec/*CEGUI_DEFAULT_IMAGE_CODEC*/)); + DynamicModule* module = NULL; + try { + DynamicModule* module = new DynamicModule(String("CEGUI") + _default_codec_name); + + _destroy_image_codec = (void(*)(ImageCodec*))module->getSymbolAddress("destroyImageCodec"); + if (!_destroy_image_codec) { + throw GenericException("Missing destroyImageCodec symbol"); + } + + ImageCodec* (*create_f)(void); + create_f = (ImageCodec* (*)(void))module->getSymbolAddress("createImageCodec"); + if (!create_f) { + throw GenericException("Missing createImageCodec symbol"); + } + _image_codec = create_f(); + } catch (...) { + delete module; + throw; + } + _image_codec_module = module; +#endif +} + + +void SoftRenderer::cleanupImageCodec() +{ + _destroy_image_codec(_image_codec); + delete _image_codec_module; +} + + +static inline uint8_t calac_pixel(uint64_t c1, uint64_t c2, uint64_t c3, uint64_t a_mul) +{ + //(c' * c" * a' * a" + c"' * 255 ^ 3 - c"' * a' * a" * 255) / 255^4 + + return uint8_t((c1 * c2 * a_mul + c3 * 255 * 255 * 255 - c3 * a_mul * 255) / (255 * 255 * 255)); +} + +inline void SoftRenderer::componnentAtPoint(int x_pos, int y_pos, + int top_left, int top_right, + int bottom_left, int bottom_right, + uint64_t& comp) +{ + int a = top_left + (((x_pos * (top_right - top_left)) + (1 << 15)) >> 16); + int b = bottom_left + (((x_pos * (bottom_right - bottom_left)) + (1 << 15)) >> 16); + comp = a + (((b - a) * y_pos + (1 << 15)) >> 16); +} + +void SoftRenderer::colourAtPoint(int x, int x_max, int y, int y_max, + const ColourIRect& colours, + uint64_t& r, uint64_t& g, + uint64_t& b, uint64_t& a) +{ + int x_pos = (x << 16) / x_max; + int y_pos = (y << 16) / y_max; + + + componnentAtPoint(x_pos, y_pos, colours.top_left.r, colours.top_right.r, + colours.bottom_left.r, colours.bottom_right.r, r); + componnentAtPoint(x_pos, y_pos, colours.top_left.g, colours.top_right.g, + colours.bottom_left.g, colours.bottom_right.g, g); + componnentAtPoint(x_pos, y_pos, colours.top_left.b, colours.top_right.b, + colours.bottom_left.b, colours.bottom_right.b, b); + componnentAtPoint(x_pos, y_pos, colours.top_left.a, colours.top_right.a, + colours.bottom_left.a, colours.bottom_right.a, a); +} + +void SoftRenderer::renderQuadWithColourRect(const QuadInfo& quad) +{ + uint32_t* src = quad.tex->_surf + quad.tex_src.top * (int)quad.tex->getWidth(); + src += quad.tex_src.left; + + + int src_width = quad.tex_src.right - quad.tex_src.left; + int src_height = quad.tex_src.bottom - quad.tex_src.top; + + int dest_width = quad.dest.right - quad.dest.left; + int dest_height = quad.dest.bottom - quad.dest.top; + + + uint32_t x_scale = (src_width << 16) / dest_width; + uint32_t y_scale = (src_height << 16) / dest_height; + + uint32_t* line = (uint32_t*)_surface + quad.dest.top * _width; + line += quad.dest.left; + + for (int i = 0; i < dest_height; line += _width, i++) { + uint32_t* pix = line; + uint32_t* src_line = src + (((i * y_scale) + (1 << 15)) >> 16) * (int)quad.tex->getWidth(); + + for (int j = 0; j < dest_width; pix++, j++) { + uint64_t r; + uint64_t g; + uint64_t b; + uint64_t a; + + colourAtPoint(j, dest_width, i, dest_height, quad.colors, r, g, b, a); + + uint8_t* tex_pix = (uint8_t*)&src_line[(((j * x_scale)+ (1 << 15)) >> 16)]; + uint64_t a_mul = a * tex_pix[3]; + + ((uint8_t *)pix)[0] = calac_pixel(tex_pix[0], b, ((uint8_t *)pix)[0], a_mul); + ((uint8_t *)pix)[1] = calac_pixel(tex_pix[1], g, ((uint8_t *)pix)[1], a_mul); + ((uint8_t *)pix)[2] = calac_pixel(tex_pix[2], r, ((uint8_t *)pix)[2], a_mul); + } + } +} + +void SoftRenderer::renderQuad(const QuadInfo& quad) +{ + if (!quad.colors.top_left.isSameColour(quad.colors.top_right) || + !quad.colors.top_left.isSameColour(quad.colors.bottom_left) || + !quad.colors.top_left.isSameColour(quad.colors.bottom_right)) { + renderQuadWithColourRect(quad); + return; + } + + + uint32_t* src = quad.tex->_surf + quad.tex_src.top * (int)quad.tex->getWidth(); + src += quad.tex_src.left; + + + int src_width = quad.tex_src.right - quad.tex_src.left; + int src_height = quad.tex_src.bottom - quad.tex_src.top; + + int dest_width = quad.dest.right - quad.dest.left; + int dest_height = quad.dest.bottom - quad.dest.top; + + + uint32_t x_scale = (src_width << 16) / dest_width; + uint32_t y_scale = (src_height << 16) / dest_height; + + uint32_t* line = (uint32_t*)_surface + quad.dest.top * _width; + line += quad.dest.left; + + uint64_t r = quad.colors.top_left.r; + uint64_t g = quad.colors.top_left.g; + uint64_t b = quad.colors.top_left.b; + uint64_t a = quad.colors.top_left.a; + + for (int i = 0; i < dest_height; line += _width, i++) { + uint32_t* pix = line; + uint32_t* src_line = src + (((i * y_scale) + (1 << 15)) >> 16) * (int)quad.tex->getWidth(); + + for (int j = 0; j < dest_width; pix++, j++) { + uint8_t* tex_pix = (uint8_t*)&src_line[(((j * x_scale)+ (1 << 15)) >> 16)]; + uint64_t a_mul = a * tex_pix[3]; + + ((uint8_t *)pix)[0] = calac_pixel(tex_pix[0], b, ((uint8_t *)pix)[0], a_mul); + ((uint8_t *)pix)[1] = calac_pixel(tex_pix[1], g, ((uint8_t *)pix)[1], a_mul); + ((uint8_t *)pix)[2] = calac_pixel(tex_pix[2], r, ((uint8_t *)pix)[2], a_mul); + } + } +} + +inline void SoftRenderer::setRGB(ColourI& dest, const colour& src) +{ + dest.r = uint8_t(src.getRed()* 255); + dest.g = uint8_t(src.getGreen() * 255); + dest.b = uint8_t(src.getBlue() * 255); + dest.a = uint8_t(src.getAlpha() * 255); +} + +void SoftRenderer::addQuad(const Rect& dest_rect, float z, const Texture* texture, + const Rect& texture_rect, const ColourRect& colours, + QuadSplitMode quad_split_mode) +{ + if (dest_rect.d_right <= dest_rect.d_left || dest_rect.d_bottom <= dest_rect.d_top) { + return; + } + + if (texture_rect.d_right <= texture_rect.d_left || + texture_rect.d_bottom <= texture_rect.d_top) { + return; + } + + QuadInfo quad; + quad.dest.top = (int)dest_rect.d_top; + quad.dest.left = (int)dest_rect.d_left; + quad.dest.bottom = (int)dest_rect.d_bottom; + quad.dest.right = (int)dest_rect.d_right; + + quad.tex = (const SoftTexture*)texture; + + quad.tex_src.top = int(texture_rect.d_top * texture->getHeight()); + quad.tex_src.bottom = int(texture_rect.d_bottom * texture->getHeight()); + quad.tex_src.left = int(texture_rect.d_left * texture->getWidth()); + quad.tex_src.right = int(texture_rect.d_right * texture->getWidth()); + + setRGB(quad.colors.top_left, colours.d_top_left); + setRGB(quad.colors.top_right, colours.d_top_right); + setRGB(quad.colors.bottom_left, colours.d_bottom_left); + setRGB(quad.colors.bottom_right, colours.d_bottom_right); + + quad.z = z; + + if (!_queueing) { + renderQuad(quad); + return; + } + + _queue.insert(quad); +} + +void SoftRenderer::doRender() +{ + QuadQueue::iterator iter = _queue.begin(); + + for (; iter != _queue.end(); ++iter) { + renderQuad(*iter); + } +} + +void SoftRenderer::clearRenderList() +{ + _queue.clear(); +} + +void SoftRenderer::setQueueingEnabled(bool val) +{ + _queueing = val; +} + +bool SoftRenderer::isQueueingEnabled() const +{ + return _queueing; +} + +Texture* SoftRenderer::createTexture() +{ + SoftTexture* texture = new SoftTexture(this); + _textures.push_back(texture); + return texture; +} + +Texture* SoftRenderer::createTexture(const String& filename, + const String& resourceGroup) +{ + SoftTexture* texture = new SoftTexture(this, filename, resourceGroup); + _textures.push_back(texture); + return texture; +} + +Texture* SoftRenderer::createTexture(float size) +{ + SoftTexture* texture = new SoftTexture(this, (uint)size); + _textures.push_back(texture); + return texture; +} + +void SoftRenderer::destroyTexture(Texture* texture) +{ + if (!texture) { + return; + } + SoftTexture* soft_texture = (SoftTexture*)texture; + _textures.remove(soft_texture); + delete soft_texture; +} + +void SoftRenderer::destroyAllTextures() +{ + while (!_textures.empty()) { + SoftTexture* texture = *_textures.begin(); + _textures.pop_front(); + delete texture; + } +} + +uint SoftRenderer::getMaxTextureSize() const +{ + return 1 << 16; +} + +float SoftRenderer::getWidth() const +{ + return (float)_width; +} + +float SoftRenderer::getHeight() const +{ + return (float)_height; +} + +Size SoftRenderer::getSize() const +{ + return Size((float)_width, (float)_height); +} + +Rect SoftRenderer::getRect() const +{ + return Rect(0, 0, (float)_width, (float)_height); +} + +uint SoftRenderer::getHorzScreenDPI() const +{ + return 96; +} + +uint SoftRenderer::getVertScreenDPI() const +{ + return 96; +} + +} + + diff --git a/client/gui/softrenderer.h b/client/gui/softrenderer.h new file mode 100644 index 0000000..939eb38 --- /dev/null +++ b/client/gui/softrenderer.h @@ -0,0 +1,131 @@ +#ifndef _directfbrenderer_h_ +#define _directfbrenderer_h_ + +#include <stdint.h> +#include <list> +#include <set> + +#include "CEGUIRenderer.h" +#include "CEGUIColourRect.h" +#include "CEGUIRect.h" + + +namespace CEGUI +{ + class SoftTexture; + class ImageCodec; + + class SoftRenderer : public Renderer + { + public: + SoftRenderer(uint8_t* surface, uint width, uint height, uint stride, + ImageCodec* codec = NULL); + virtual ~SoftRenderer(); + + void reset_surface(uint8_t* surface, uint width, uint height, uint stride); + + virtual void addQuad(const Rect& dest_rect, float z, const Texture* tex, + const Rect& texture_rect, const ColourRect& colours, + QuadSplitMode quad_split_mode); + virtual void doRender(); + virtual void clearRenderList(); + virtual void setQueueingEnabled(bool setting); + virtual bool isQueueingEnabled() const; + + virtual Texture* createTexture(); + virtual Texture* createTexture(const String& filename, + const String& resourceGroup); + virtual Texture* createTexture(float size); + virtual void destroyTexture(Texture* texture); + virtual void destroyAllTextures(); + virtual uint getMaxTextureSize() const; + + virtual float getWidth() const; + virtual float getHeight() const; + virtual Size getSize() const; + virtual Rect getRect() const; + + virtual uint getHorzScreenDPI() const; + virtual uint getVertScreenDPI() const; + + ImageCodec* getImageCodec() { return _image_codec;} + + private: + void setupImageCodec(); + void cleanupImageCodec(); + struct QuadInfo; + void renderQuad(const QuadInfo& quad); + void renderQuadWithColourRect(const QuadInfo& quad); + + class ColourI { + public: + + bool isSameColour(const ColourI& other) const + { + return other.r == r && other.g == g && other.b == b && other.a == a; + } + + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + + static inline void setRGB(ColourI& dest, const colour& src); + static inline void componnentAtPoint(int x_pos, int y_pos, + int top_left, int top_right, + int bottom_left, int bottom_right, + uint64_t& comp); + + struct ColourIRect { + ColourI top_left; + ColourI top_right; + ColourI bottom_left; + ColourI bottom_right; + }; + + static void colourAtPoint(int x, int x_max, int y, int y_max, + const ColourIRect& colours, + uint64_t& r, uint64_t& g, + uint64_t& b, uint64_t& a); + + private: + uint8_t* _surface; + int _width; + int _height; + ImageCodec* _image_codec; + DynamicModule* _image_codec_module; + void (*_destroy_image_codec)(ImageCodec*); + bool _queueing; + + struct RectI { + int left; + int top; + int right; + int bottom; + }; + + struct QuadInfo { + RectI dest; + const SoftTexture* tex; + RectI tex_src; + ColourIRect colors; + float z; + + bool operator < (const QuadInfo& other) const + { + return z > other.z; + } + }; + + typedef std::multiset<QuadInfo> QuadQueue; + QuadQueue _queue; + + typedef std::list<SoftTexture *> TexturesList; + TexturesList _textures; + }; +} + +#endif + + diff --git a/client/gui/softtexture.cpp b/client/gui/softtexture.cpp new file mode 100644 index 0000000..562edea --- /dev/null +++ b/client/gui/softtexture.cpp @@ -0,0 +1,124 @@ +#include "common.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "softtexture.h" +#include "softrenderer.h" + +#include "CEGUIImageCodec.h" +#include "CEGUISystem.h" +#include "CEGUIExceptions.h" + +namespace CEGUI +{ + + +SoftTexture::SoftTexture(Renderer* owner) + : Texture (owner) + , _surf (NULL) + , _width (0) + , _height (0) +{ + +} + +SoftTexture::SoftTexture(Renderer* owner, uint size) + : Texture (owner) + , _surf (new uint32[size * size]) + , _width (size) + , _height (size) +{ + +} + +SoftTexture::SoftTexture(Renderer* owner, const String& filename, + const String& resourceGroup) + : Texture (owner) + , _surf (NULL) + , _width (0) + , _height (0) +{ + loadFromFile(filename, resourceGroup); +} + + +SoftTexture::~SoftTexture() +{ + freeSurf(); +} + +void SoftTexture::freeSurf() +{ + _width = _height = 0; + delete[] _surf; + _surf = NULL; +} + +void SoftTexture::loadFromFile(const String& filename, const String& resourceGroup) +{ + freeSurf(); + SoftRenderer* renderer = static_cast<SoftRenderer*>(getRenderer()); + RawDataContainer texture_file; + ResourceProvider* resource_provider = System::getSingleton().getResourceProvider(); + resource_provider->loadRawDataContainer(filename, texture_file, resourceGroup); + ImageCodec *codec = renderer->getImageCodec(); + Texture* res = codec->load(texture_file, this); + resource_provider->unloadRawDataContainer(texture_file); + if (!res) { + throw RendererException("load from file failed"); + } +} + +void SoftTexture::loadFromMemory(const void* buffPtr, uint buffWidth, + uint buffHeight, + PixelFormat pixelFormat) +{ + freeSurf(); + _surf = new uint32[buffWidth * buffHeight]; + _width = buffWidth; + _height = buffHeight; + + switch (pixelFormat) { + case PF_RGBA: { + const uint32_t *src = static_cast<const uint32_t *>(buffPtr); + uint32* line = _surf; + uint32* end_line = _surf + _width * _height; + for (int i = 0; line != end_line; line += _width, i++) { + uint32* pixel = line; + uint32* end_pixel = pixel + _width; + for (; pixel != end_pixel; pixel++, src++) { + ((uint8_t*)pixel)[0] = ((uint8_t*)src)[2]; + ((uint8_t*)pixel)[1] = ((uint8_t*)src)[1]; + ((uint8_t*)pixel)[2] = ((uint8_t*)src)[0]; + ((uint8_t*)pixel)[3] = ((uint8_t*)src)[3]; + } + } + break; + } + case PF_RGB: { + const uint8_t *src = static_cast<const uint8_t *>(buffPtr); + uint32* line = _surf; + uint32* end_line = _surf + _width * _height; + for (int i = 0; line != end_line; line += _width, i++) { + uint8* pixel = (uint8*)line; + uint8* end_pixel = (uint8*)(line + _width); + for (; pixel != end_pixel; pixel += 4, src += 3) { + pixel[2] = src[0]; + pixel[1] = src[1]; + pixel[0] = src[2]; + pixel[3] = 0xff; + } + } + break; + } + default: + throw RendererException("invalid pixel format"); + } +} + + +} + diff --git a/client/gui/softtexture.h b/client/gui/softtexture.h new file mode 100644 index 0000000..37617f2 --- /dev/null +++ b/client/gui/softtexture.h @@ -0,0 +1,40 @@ + +#ifndef _softtexture_h_ +#define _softtexture_h_ + +#include <stdint.h> +#include "CEGUIBase.h" +#include "CEGUITexture.h" + +namespace CEGUI +{ + class SoftTexture : public Texture + { + public: + SoftTexture(Renderer* owner); + SoftTexture(Renderer* owner, uint size); + SoftTexture(Renderer* owner, const String& filename, + const String& resourceGroup); + virtual ~SoftTexture(); + + virtual ushort getWidth(void) const { return _width;} + virtual ushort getHeight(void) const { return _height;} + + virtual void loadFromFile(const String& filename, const String& resourceGroup); + virtual void loadFromMemory(const void* buffPtr, uint buffWidth, uint buffHeight, + PixelFormat pixelFormat); + + private: + void freeSurf(); + + private: + uint32_t* _surf; + ushort _width; + ushort _height; + + friend class SoftRenderer; + }; +} + +#endif + diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj index 302d391..2741ae5 100644 --- a/client/windows/redc.vcproj +++ b/client/windows/redc.vcproj @@ -41,8 +41,8 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - AdditionalIncludeDirectories=".;..;..\..\common;..\..\common\win;"..\..\common\win\my_getopt-1.5";"$(SPICE_LIBS)\include";"$(SPICE_LIBS)\include\qcairo";"$(SPICE_LIBS)\include\ffmpeg"" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;CAIRO_CANVAS_ACCESS_TEST;CAIRO_CANVAS_CACHE;CAIRO_CANVAS_CACH_IS_SHARED;RED_DEBUG;CAIRO_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB" + AdditionalIncludeDirectories=".;..;..\..\common;..\..\common\win;"..\..\common\win\my_getopt-1.5";"$(SPICE_LIBS)\include";"$(SPICE_LIBS)\include\qcairo";"$(SPICE_LIBS)\include\ffmpeg";"$(SPICE_LIBS)\include\CEGUI-0.6.2"" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;CAIRO_CANVAS_ACCESS_TEST;CAIRO_CANVAS_CACHE;CAIRO_CANVAS_CACH_IS_SHARED;RED_DEBUG;CAIRO_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC" MinimalRebuild="false" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -64,7 +64,7 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="log4cppD.lib libqcairo-2.dll.lib libeay32MTd.lib ssleay32MTd.lib ws2_32.lib msimg32.lib winmm.lib avcodec-51.lib avutil-49.lib libcelt_0_5_1D.lib pthreadsD.lib version.lib" + AdditionalDependencies="log4cppD.lib libqcairo-2.dll.lib libeay32MTd.lib ssleay32MTd.lib ws2_32.lib msimg32.lib winmm.lib avcodec-51.lib avutil-49.lib libcelt_0_5_1D.lib pthreadsD.lib version.lib CEGUIBase_Static_d.lib CEGUITGAImageCodec_Static_d.lib CEGUIExpatParser_Static_d.lib freetype235MT_D.lib libexpatMT_D.lib pcre_D.lib CEGUIFalagardWRBase_Static_d.lib" OutputFile="$(OutDir)\spicec.exe" LinkIncremental="2" AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib"" @@ -124,8 +124,8 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalIncludeDirectories=".;..;..\..\common;..\..\common\win;"..\..\common\win\my_getopt-1.5";"$(SPICE_LIBS)\include";"$(SPICE_LIBS)\include\qcairo";"$(SPICE_LIBS)\include\ffmpeg"" - PreprocessorDefinitions="WIN32;_WINDOWS;CAIRO_CANVAS_ACCESS_TEST;CAIRO_CANVAS_CACHE;CAIRO_CANVAS_NO_CHUNKS;CAIRO_CANVAS_CACH_IS_SHARED;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB" + AdditionalIncludeDirectories=".;..;..\..\common;..\..\common\win;"..\..\common\win\my_getopt-1.5";"$(SPICE_LIBS)\include";"$(SPICE_LIBS)\include\qcairo";"$(SPICE_LIBS)\include\ffmpeg";"$(SPICE_LIBS)\include\CEGUI-0.6.2"" + PreprocessorDefinitions="WIN32;_WINDOWS;CAIRO_CANVAS_ACCESS_TEST;CAIRO_CANVAS_CACHE;CAIRO_CANVAS_NO_CHUNKS;CAIRO_CANVAS_CACH_IS_SHARED;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC" RuntimeLibrary="0" UsePrecompiledHeader="0" WarningLevel="3" @@ -144,7 +144,7 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="log4cpp.lib libqcairo-2.dll.lib libeay32MT.lib ssleay32MT.lib ws2_32.lib msimg32.lib winmm.lib avcodec-51.lib avutil-49.lib libcelt_0_5_1.lib pthreads.lib version.lib" + AdditionalDependencies="log4cpp.lib libqcairo-2.dll.lib libeay32MT.lib ssleay32MT.lib ws2_32.lib msimg32.lib winmm.lib avcodec-51.lib avutil-49.lib libcelt_0_5_1.lib pthreads.lib version.lib CEGUIBase_Static.lib CEGUITGAImageCodec_Static.lib CEGUIExpatParser_Static.lib freetype235MT.lib libexpatMT.lib pcre.lib CEGUIFalagardWRBase_Static.lib" OutputFile="$(OutDir)\spicec.exe" LinkIncremental="1" AdditionalLibraryDirectories=""$(SPICE_LIBS)\lib"" @@ -383,6 +383,14 @@ > </File> <File + RelativePath="..\gui\softrenderer.cpp" + > + </File> + <File + RelativePath="..\gui\softtexture.cpp" + > + </File> + <File RelativePath="..\threads.cpp" > </File> @@ -573,6 +581,14 @@ > </File> <File + RelativePath="..\gui\softrenderer.h" + > + </File> + <File + RelativePath="..\gui\softtexture.h" + > + </File> + <File RelativePath="..\threads.h" > </File> diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am index 99f0c26..072548d 100644 --- a/client/x11/Makefile.am +++ b/client/x11/Makefile.am @@ -22,6 +22,7 @@ INCLUDES = \ $(CELT051_CFLAGS) \ $(SSL_CFLAGS) \ $(XRANDR_CFLAGS) \ + $(CEGUI_CFLAGS) \ $(WARN_CFLAGS) \ $(NULL) @@ -101,7 +102,11 @@ RED_COMMON_SRCS = \ $(top_srcdir)/client/tunnel_channel.h \ $(top_srcdir)/client/utils.cpp \ $(top_srcdir)/client/utils.h \ - $(top_srcdir)/client/icon.h \ + $(top_srcdir)/client/icon.h \ + $(top_srcdir)/client/gui/softrenderer.h \ + $(top_srcdir)/client/gui/softrenderer.cpp \ + $(top_srcdir)/client/gui/softtexture.h \ + $(top_srcdir)/client/gui/softtexture.cpp \ $(NULL) bin_PROGRAMS = spicec @@ -141,7 +146,7 @@ spicec_LDFLAGS = \ $(LOG4CPP_LIBS) \ $(CELT051_LIBS) \ $(SSL_LIBS) \ - $(SPICEC_STATIC_LINKAGE_BDYNAMIC) + $(CEGUI_LIBS) spicec_LDADD = \ $(QCAIRO_LIBS) \ @@ -149,5 +154,6 @@ spicec_LDADD = \ $(ALSA_LIBS) \ $(GL_LIBS) \ $(XRANDR_LIBS) \ + $(CEGUI_LIBS) \ -lrt diff --git a/configure.ac b/configure.ac index ebb15a0..abba331 100644 --- a/configure.ac +++ b/configure.ac @@ -105,6 +105,11 @@ AC_SUBST(LOG4CPP_CFLAGS) AC_SUBST(LOG4CPP_LIBS) SPICE_REQUIRES+=" log4cpp" +PKG_CHECK_MODULES(CEGUI, CEGUI = 0.6.2) +AC_SUBST(CEGUI_CFLAGS) +AC_SUBST(CEGUI_LIBS) +SPICE_REQUIRES+=" CEGUI" + PKG_CHECK_MODULES(SLIRP, slirp) AC_SUBST(SLIRP_CFLAGS) AC_SUBST(SLIRP_LIBS) |
From: Yaniv K. <yk...@re...> - 2009-12-28 10:36:56
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit 2dbaf8c00c28770e48cbfc6ab3300000118d22ec Author: Yaniv Kamay <yk...@re...> Date: Sat Dec 26 17:24:37 2009 +0200 client: smiplify DisconnectedEvent diff --git a/client/application.cpp b/client/application.cpp index 9add9d3..e96a9c4 100644 --- a/client/application.cpp +++ b/client/application.cpp @@ -62,21 +62,7 @@ void ConnectedEvent::response(AbstractProcessLoop& events_loop) void DisconnectedEvent::response(AbstractProcessLoop& events_loop) { Application* app = static_cast<Application*>(events_loop.get_owner()); -#ifdef RED_DEBUG - app->show_splash(0); -#else - app->do_quit(SPICEC_ERROR_CODE_SUCCESS); -#endif -} - -void ConnectionErrorEvent::response(AbstractProcessLoop& events_loop) -{ - Application* app = static_cast<Application*>(events_loop.get_owner()); -#ifdef RED_DEBUG - app->show_splash(0); -#else - app->do_quit(_error_code); -#endif + app->on_disconnected(_error_code); } void VisibilityEvent::response(AbstractProcessLoop& events_loop) @@ -601,6 +587,16 @@ void Application::unpress_all() void Application::on_connected() { + +} + +void Application::on_disconnected(int error_code) +{ +#ifdef RED_DEBUG + show_splash(0); +#else + do_quit(error_code); +#endif } void Application::on_visibility_start(int screen_id) diff --git a/client/application.h b/client/application.h index 757ee3a..c2b81e6 100644 --- a/client/application.h +++ b/client/application.h @@ -44,13 +44,10 @@ public: class DisconnectedEvent: public Event { public: + DisconnectedEvent() : _error_code (SPICEC_ERROR_CODE_SUCCESS) {} + DisconnectedEvent(int error_code) : _error_code (error_code) {} virtual void response(AbstractProcessLoop& events_loop); -}; -class ConnectionErrorEvent: public Event { -public: - ConnectionErrorEvent(int error_code) : _error_code (error_code) {} - virtual void response(AbstractProcessLoop& events_loop); private: int _error_code; }; @@ -152,6 +149,7 @@ public: virtual void on_monitors_change(); virtual void on_display_mode_change(); void on_connected(); + void on_disconnected(int spice_error_code); void on_disconnecting(); void on_visibility_start(int screen_id); diff --git a/client/red_client.cpp b/client/red_client.cpp index bc9e112..8fcb81d 100644 --- a/client/red_client.cpp +++ b/client/red_client.cpp @@ -469,14 +469,8 @@ void RedClient::on_channel_disconnected(RedChannel& channel) if (_notify_disconnect) { _notify_disconnect = false; int connection_error = channel.get_connection_error(); - if (connection_error == SPICEC_ERROR_CODE_SUCCESS) { - AutoRef<DisconnectedEvent> disconn_event(new DisconnectedEvent()); - LOG_INFO("disconneted"); - push_event(*disconn_event); - } else { - AutoRef<ConnectionErrorEvent> error_event(new ConnectionErrorEvent(connection_error)); - push_event(*error_event); - } + AutoRef<DisconnectedEvent> disconn_event(new DisconnectedEvent(connection_error)); + push_event(*disconn_event); } disconnect_channels(); RedPeer::disconnect(); |
From: Yaniv K. <yk...@re...> - 2009-12-28 10:36:38
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit 62248734bdf23d70e3ec16d1881d7c96ca9f85db Author: Yaniv Kamay <yk...@re...> Date: Sat Dec 26 17:11:18 2009 +0200 client: move visibility change logic from screen to app diff --git a/client/application.cpp b/client/application.cpp index 724eb33..9add9d3 100644 --- a/client/application.cpp +++ b/client/application.cpp @@ -79,6 +79,12 @@ void ConnectionErrorEvent::response(AbstractProcessLoop& events_loop) #endif } +void VisibilityEvent::response(AbstractProcessLoop& events_loop) +{ + Application* app = static_cast<Application*>(events_loop.get_owner()); + app->on_visibility_start(_screen_id); +} + void MonitorsQuery::do_response(AbstractProcessLoop& events_loop) { Monitor* mon; @@ -597,6 +603,15 @@ void Application::on_connected() { } +void Application::on_visibility_start(int screen_id) +{ + if (screen_id) { + return; + } + + hide_splash(0); +} + void Application::on_disconnecting() { release_capture(); diff --git a/client/application.h b/client/application.h index c5e0e14..757ee3a 100644 --- a/client/application.h +++ b/client/application.h @@ -55,6 +55,16 @@ private: int _error_code; }; +class VisibilityEvent: public Event { +public: + VisibilityEvent(int screen_id) : _screen_id (screen_id) {} + + virtual void response(AbstractProcessLoop& events_loop); + +private: + int _screen_id; +}; + struct MonitorInfo { int depth; Point size; @@ -143,6 +153,7 @@ public: virtual void on_display_mode_change(); void on_connected(); void on_disconnecting(); + void on_visibility_start(int screen_id); bool rearrange_monitors(RedScreen& screen); void enter_full_screen(); diff --git a/client/display_channel.cpp b/client/display_channel.cpp index 0050a21..9d10bc7 100644 --- a/client/display_channel.cpp +++ b/client/display_channel.cpp @@ -88,22 +88,6 @@ private: AutoRef<RedScreen> _screen; }; -class DisplayMarkEvent: public Event { -public: - DisplayMarkEvent(int screen_id) - : _screen_id (screen_id) - { - } - - virtual void response(AbstractProcessLoop& events_loop) - { - static_cast<Application*>(events_loop.get_owner())->hide_splash(_screen_id); - } - -private: - int _screen_id; -}; - #define CLIP_ARRAY_SIZE 1500 #define CLIP_ARRAY_SHIFT 500 @@ -1290,7 +1274,7 @@ void DisplayChannel::handle_mark(RedPeer::InMessage *message) area.right = _x_res; area.bottom = _y_res; - AutoRef<DisplayMarkEvent> event(new DisplayMarkEvent(get_id())); + AutoRef<VisibilityEvent> event(new VisibilityEvent(get_id())); get_client().push_event(*event); set_rect_area(area); } |
From: Yaniv K. <yk...@re...> - 2009-12-28 10:36:07
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit c6435ea02bb43e8f5285c5966283cbbf92e23f4e Author: Yaniv Kamay <yk...@re...> Date: Sat Dec 26 17:00:15 2009 +0200 client: wait for disconnect state in RedClient::connect() diff --git a/client/red_client.cpp b/client/red_client.cpp index 25fd5c7..bc9e112 100644 --- a/client/red_client.cpp +++ b/client/red_client.cpp @@ -422,10 +422,15 @@ RedPeer::ConnectionOptions::Type RedClient::get_connection_options(uint32_t chan void RedClient::connect() { - //todo wait for disconnect state - if (_connection_id || !abort_channels()) { + if (_connection_id) { return; } + + while (!abort_channels()) { + _application.process_events_queue(); + Platform::msleep(100); + } + _pixmap_cache.clear(); _glz_window.clear(); memset(_sync_info, 0, sizeof(_sync_info)); |
From: Yaniv K. <yk...@re...> - 2009-12-28 10:35:48
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit cced1b1cff4002e2402936ff033ce985668e59e5 Author: Yaniv Kamay <yk...@re...> Date: Mon Dec 28 00:17:42 2009 +0200 client: improve screen resizing Screen now have to modes locked and unlocked. In unlocked mode, the application can change screen size and so reduce resolution changing. The application can also choose to change window size while not in full screen mode. In locked mode the application must ewtain locker screen size setting. diff --git a/client/application.cpp b/client/application.cpp index 8345f39..724eb33 100644 --- a/client/application.cpp +++ b/client/application.cpp @@ -226,7 +226,11 @@ void GUILayer::set_sticky(bool is_on) void GUILayer::on_size_changed() { - set_info_mode(); + if (_splash_mode) { + set_splash_mode(); + } else { + set_info_mode(); + } } void StickyKeyTimer::response(AbstractProcessLoop& events_loop) @@ -499,31 +503,35 @@ RedScreen* Application::get_screen(int id) } if (!(screen = _screens[id])) { - Monitor* mon; + Monitor* mon = find_monitor(id); + Point size; - if (_client.is_auto_display_res() && (mon = find_monitor(id))) { + if (_full_screen && mon) { Point size = mon->get_size(); - screen = _screens[id] = new RedScreen(*this, id, _title, size.x, size.y); } else { - screen = _screens[id] = new RedScreen(*this, id, _title, SCREEN_INIT_WIDTH, - SCREEN_INIT_HEIGHT); + size.x = SCREEN_INIT_WIDTH; + size.y = SCREEN_INIT_HEIGHT; } - if (_full_screen) { - bool capture; - - mon = get_monitor(id); - capture = release_capture(); - screen->set_monitor(mon); - position_screens(); - screen->show_full_screen(); - prepare_monitors(); - - if (capture) { - _main_screen->activate(); - _main_screen->capture_mouse(); + screen = _screens[id] = new RedScreen(*this, id, _title, size.x, size.y); + + if (id != 0) { + if (_full_screen) { + bool capture; + + mon = get_monitor(id); + capture = release_capture(); + screen->set_monitor(mon); + position_screens(); + screen->show_full_screen(); + prepare_monitors(); + + if (capture) { + _main_screen->activate(); + _main_screen->capture_mouse(); + } + } else { + screen->show(false, _main_screen); } - } else if (id != 0) { - screen->show(false, _main_screen); } } else { screen = screen->ref(); @@ -962,6 +970,15 @@ void Application::on_app_deactivated() #endif } +void Application::on_screen_unlocked(RedScreen& screen) +{ + if (_full_screen) { + return; + } + + screen.resize(SCREEN_INIT_WIDTH, SCREEN_INIT_HEIGHT); +} + bool Application::rearrange_monitors(RedScreen& screen) { if (!_full_screen) { @@ -1012,14 +1029,20 @@ void Application::assign_monitors() void Application::prepare_monitors() { + //todo: test match of monitors size/position against real world size/position for (int i = 0; i < (int)_screens.size(); i++) { Monitor* mon; if (_screens[i] && (mon = _screens[i]->get_monitor())) { - Point size = _screens[i]->get_size(); - mon->set_mode(size.x, size.y); + + if (_screens[i]->is_size_locked()) { + Point size = _screens[i]->get_size(); + mon->set_mode(size.x, size.y); + } else { + Point size = mon->get_size(); + _screens[i]->resize(size.x, size.y); + } } } - //todo: test match of monitors size/position against real world size/position } void Application::restore_monitors() @@ -1097,6 +1120,16 @@ void Application::enter_full_screen() _full_screen = true; } +void Application::restore_screens_size() +{ + for (int i = 0; i < (int)_screens.size(); i++) { + if (_screens[i]->is_size_locked()) { + continue; + } + _screens[i]->resize(SCREEN_INIT_WIDTH, SCREEN_INIT_HEIGHT); + } +} + void Application::exit_full_screen() { if (!_full_screen) { @@ -1116,6 +1149,7 @@ void Application::exit_full_screen() } restore_monitors(); _full_screen = false; + restore_screens_size(); show(); _main_screen->activate(); } @@ -1606,12 +1640,6 @@ bool Application::process_cmd_line(int argc, char** argv) } _client.init(host.c_str(), port, sport, password.c_str(), auto_display_res); - if (auto_display_res) { - Monitor* mon = find_monitor(0); - ASSERT(mon); - Point size = mon->get_size(); - _main_screen->set_mode(size.x, size.y, 32); - } if (full_screen) { enter_full_screen(); diff --git a/client/application.h b/client/application.h index da2d421..c5e0e14 100644 --- a/client/application.h +++ b/client/application.h @@ -125,6 +125,7 @@ public: RedScreen* find_screen(int id); RedScreen* get_screen(int id); + void on_screen_unlocked(RedScreen& screen); void on_screen_destroyed(int id, bool was_captured); void on_mouse_motion(int dx, int dy, int buttons_state); void on_mouse_down(int button, int buttons_state); @@ -176,6 +177,7 @@ private: bool do_connect(); bool do_disconnect(); + void restore_screens_size(); Monitor* find_monitor(int id); Monitor* get_monitor(int id); void init_monitors(); diff --git a/client/display_channel.cpp b/client/display_channel.cpp index 9f8fba8..0050a21 100644 --- a/client/display_channel.cpp +++ b/client/display_channel.cpp @@ -60,7 +60,8 @@ public: { Application* app = (Application*)events_loop.get_owner(); _channel.destroy_canvas(); - _channel.screen()->set_mode(_width, _height, _depth); + _channel.screen()->lock_size(); + _channel.screen()->resize(_width, _height); _channel.create_canvas(app->get_canvas_types(), _width, _height, _depth); } @@ -71,6 +72,22 @@ private: int _depth; }; +class UnlockScreenEvent: public Event { +public: + UnlockScreenEvent(RedScreen* screen) + : _screen (screen->ref()) + { + } + + virtual void response(AbstractProcessLoop& events_loop) + { + (*_screen)->unlock_size(); + } + +private: + AutoRef<RedScreen> _screen; +}; + class DisplayMarkEvent: public Event { public: DisplayMarkEvent(int screen_id) @@ -1088,9 +1105,14 @@ 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()); + if (screen()) { + AutoRef<UnlockScreenEvent> unlock_event(new UnlockScreenEvent(screen())); + get_client().push_event(*unlock_event); + detach_from_screen(get_client().get_application()); + } get_client().deactivate_interval_timer(*_streams_timer); AutoRef<SyncEvent> sync_event(new SyncEvent()); get_client().push_event(*sync_event); @@ -1280,7 +1302,12 @@ void DisplayChannel::handle_reset(RedPeer::InMessage *message) if (_canvas.get()) { _canvas->clear(); } + AutoRef<ResetTimer> reset_timer(new ResetTimer(screen()->ref(), get_client())); + + AutoRef<UnlockScreenEvent> unlock_event(new UnlockScreenEvent(screen())); + get_client().push_event(*unlock_event); + detach_from_screen(get_client().get_application()); _palette_cache.clear(); diff --git a/client/screen.cpp b/client/screen.cpp index e9bae8b..29b40bf 100644 --- a/client/screen.cpp +++ b/client/screen.cpp @@ -83,6 +83,7 @@ RedScreen::RedScreen(Application& owner, int id, const std::wstring& name, int w , _periodic_update (false) , _key_interception (false) , _update_by_timer (true) + , _size_locked (false) , _forec_update_timer (0) , _update_timer (new UpdateTimer(this)) , _composit_area (NULL) @@ -148,7 +149,7 @@ void RedScreen::show(bool activate, RedScreen* pos) RedScreen* RedScreen::ref() { - _refs++; + ++_refs; return this; } @@ -179,7 +180,7 @@ void RedScreen::adjust_window_rect(int x, int y) _window.move_and_resize(x, y, _size.x, _size.y); } -void RedScreen::set_mode(int width, int height, int depth) +void RedScreen::resize(int width, int height) { RecurciveLock lock(_update_lock); _size.x = width; @@ -204,6 +205,18 @@ void RedScreen::set_mode(int width, int height, int depth) notify_new_size(); } +void RedScreen::lock_size() +{ + ASSERT(!_size_locked); + _size_locked = true; +} + +void RedScreen::unlock_size() +{ + _size_locked = false; + _owner.on_screen_unlocked(*this); +} + void RedScreen::set_name(const std::wstring& name) { if (!name.empty()) { diff --git a/client/screen.h b/client/screen.h index 3321c2f..5952fe8 100644 --- a/client/screen.h +++ b/client/screen.h @@ -58,7 +58,7 @@ 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 resize(int width, int height); void set_name(const std::wstring& name); uint64_t invalidate(const Rect& rect, bool urgent); void invalidate(const QRegion ®ion); @@ -68,6 +68,9 @@ public: bool intercepts_sys_key() { return _key_interception;} Point get_size() { return _size;} bool has_monitor() { return _monitor != 0;} + void lock_size(); + void unlock_size(); + bool is_size_locked() { return _size_locked;} void set_monitor(Monitor *monitor) { _monitor = monitor;} Monitor* get_monitor() { return _monitor;} RedWindow* get_window() { return &_window;} @@ -154,7 +157,7 @@ private: private: Application& _owner; int _id; - int _refs; + AtomicCount _refs; std::wstring _name; RedWindow _window; std::vector<ScreenLayer*> _layes; @@ -167,6 +170,7 @@ private: bool _periodic_update; bool _key_interception; bool _update_by_timer; + bool _size_locked; int _forec_update_timer; AutoRef<UpdateTimer> _update_timer; RedDrawable* _composit_area; |
From: Yaniv K. <yk...@re...> - 2009-12-28 10:35:28
|
repository: /home/tlv/ykamay/open_spice_upload/spice branch: master commit 941ba9bf5ca9a8812e7893848943c2cec6a5e6a6 Author: Yaniv Kamay <yk...@re...> Date: Sat Dec 26 16:01:45 2009 +0200 client: restore mouse capture state after screen resizing diff --git a/client/screen.cpp b/client/screen.cpp index 39c9dbc..e9bae8b 100644 --- a/client/screen.cpp +++ b/client/screen.cpp @@ -192,7 +192,14 @@ void RedScreen::set_mode(int width, int height, int depth) capture_mouse(); } } else { + bool cuptur = is_mouse_captured(); + if (cuptur) { + relase_mouse(); + } _window.resize(_size.x, _size.y); + if (_active && cuptur) { + capture_mouse(); + } } notify_new_size(); } @@ -677,7 +684,6 @@ void RedScreen::on_activate() _owner.on_activate_screen(this); } - void RedScreen::on_start_key_interception() { _key_interception = true; |