summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/application.cpp553
-rw-r--r--client/application.h70
-rw-r--r--client/gui/gui.cpp1354
-rw-r--r--client/gui/gui.h120
-rw-r--r--client/gui/resource_provider.cpp128
-rw-r--r--client/gui/resource_provider.h40
-rw-r--r--client/gui/softrenderer.cpp7
-rw-r--r--client/gui/softrenderer.h1
-rw-r--r--client/platform.h1
-rw-r--r--client/red_channel.cpp3
-rw-r--r--client/red_client.cpp20
-rw-r--r--client/red_client.h12
-rw-r--r--client/screen.h2
-rw-r--r--client/utils.cpp11
-rw-r--r--client/utils.h2
-rw-r--r--client/windows/platform.cpp5
-rw-r--r--client/windows/redc.vcproj16
-rw-r--r--client/x11/Makefile.am4
-rw-r--r--client/x11/platform.cpp9
19 files changed, 2184 insertions, 174 deletions
diff --git a/client/application.cpp b/client/application.cpp
index e96a9c4a..2f24307d 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 c2b81e6c..5c607025 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 00000000..1bbf3c42
--- /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(&regin);
+
+ 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(&regin, &r);
+
+ }
+ set_area(regin);
+ region_destroy(&regin);
+}
+
+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);
+ break;
+ case REDC_MOUSE_MBUTTON:
+ _gui_system->injectMouseButtonUp(CEGUI::MiddleButton);
+ break;
+ case REDC_MOUSE_RBUTTON:
+ _gui_system->injectMouseButtonUp(CEGUI::RightButton);
+ break;
+ case REDC_MOUSE_UBUTTON:
+ case REDC_MOUSE_DBUTTON:
+ break;
+ default:
+ THROW("invalid RedButton %d", button);
+ }
+ conditional_update();
+}
+
+void GUI::on_pointer_leave()
+{
+ CEGUI::MouseCursor::getSingleton().hide();
+ invalidate();
+}
+
+#define KEY_CASE(a, b) \
+ case a: \
+ return CEGUI::Key::b
+
+static inline CEGUI::Key::Scan red_ket_cegui_scan(RedKey key)
+{
+ switch (key) {
+ KEY_CASE(REDKEY_ESCAPE, Escape);
+ KEY_CASE(REDKEY_1, One);
+ KEY_CASE(REDKEY_2, Two);
+ KEY_CASE(REDKEY_3, Three);
+ KEY_CASE(REDKEY_4, Four);
+ KEY_CASE(REDKEY_5, Five);
+ KEY_CASE(REDKEY_6, Six);
+ KEY_CASE(REDKEY_7, Seven);
+ KEY_CASE(REDKEY_8, Eight);
+ KEY_CASE(REDKEY_9, Nine);
+ KEY_CASE(REDKEY_0, Zero);
+ KEY_CASE(REDKEY_MINUS, Minus);
+ KEY_CASE(REDKEY_EQUALS, Equals);
+ KEY_CASE(REDKEY_BACKSPACE, Backspace);
+ KEY_CASE(REDKEY_TAB, Tab);
+ KEY_CASE(REDKEY_Q, Q);
+ KEY_CASE(REDKEY_W, W);
+ KEY_CASE(REDKEY_E, E);
+ KEY_CASE(REDKEY_R, R);
+ KEY_CASE(REDKEY_T, T);
+ KEY_CASE(REDKEY_Y, Y);
+ KEY_CASE(REDKEY_U, U);
+ KEY_CASE(REDKEY_I, I);
+ KEY_CASE(REDKEY_O, O);
+ KEY_CASE(REDKEY_P, P);
+ KEY_CASE(REDKEY_L_BRACKET, LeftBracket);
+ KEY_CASE(REDKEY_R_BRACKET, RightBracket);
+ KEY_CASE(REDKEY_ENTER, Return);
+ KEY_CASE(REDKEY_L_CTRL, LeftControl);
+ KEY_CASE(REDKEY_A, A);
+ KEY_CASE(REDKEY_S, S);
+ KEY_CASE(REDKEY_D, D);
+ KEY_CASE(REDKEY_F, F);
+ KEY_CASE(REDKEY_G, G);
+ KEY_CASE(REDKEY_H, H);
+ KEY_CASE(REDKEY_J, J);
+ KEY_CASE(REDKEY_K, K);
+ KEY_CASE(REDKEY_L, L);
+ KEY_CASE(REDKEY_SEMICOLON, Semicolon);
+ KEY_CASE(REDKEY_QUOTE, Apostrophe);
+
+ KEY_CASE(REDKEY_BACK_QUOTE, Grave);
+ KEY_CASE(REDKEY_L_SHIFT, LeftShift);
+ KEY_CASE(REDKEY_BACK_SLASH, Backslash);
+ KEY_CASE(REDKEY_Z, Z);
+ KEY_CASE(REDKEY_X, X);
+ KEY_CASE(REDKEY_C, C);
+ KEY_CASE(REDKEY_V, V);
+ KEY_CASE(REDKEY_B, B);
+ KEY_CASE(REDKEY_N, N);
+ KEY_CASE(REDKEY_M, M);
+ KEY_CASE(REDKEY_COMMA, Comma);
+ KEY_CASE(REDKEY_PERIOD, Period);
+ KEY_CASE(REDKEY_SLASH, Slash);
+ KEY_CASE(REDKEY_R_SHIFT, RightShift);
+ KEY_CASE(REDKEY_PAD_MULTIPLY, Multiply);
+ KEY_CASE(REDKEY_L_ALT, LeftAlt);
+ KEY_CASE(REDKEY_SPACE, Space);
+ KEY_CASE(REDKEY_CAPS_LOCK, Capital);
+ KEY_CASE(REDKEY_F1, F1);
+ KEY_CASE(REDKEY_F2, F2);
+ KEY_CASE(REDKEY_F3, F3);
+ KEY_CASE(REDKEY_F4, F4);
+ KEY_CASE(REDKEY_F5, F5);
+ KEY_CASE(REDKEY_F6, F6);
+ KEY_CASE(REDKEY_F7, F7);
+ KEY_CASE(REDKEY_F8, F8);
+ KEY_CASE(REDKEY_F9, F9);
+ KEY_CASE(REDKEY_F10, F10);
+ KEY_CASE(REDKEY_NUM_LOCK, NumLock);
+ KEY_CASE(REDKEY_SCROLL_LOCK, ScrollLock);
+ KEY_CASE(REDKEY_PAD_7, Numpad7);
+ KEY_CASE(REDKEY_PAD_8, Numpad8);
+ KEY_CASE(REDKEY_PAD_9, Numpad9);
+ KEY_CASE(REDKEY_PAD_MINUS, Subtract);
+ KEY_CASE(REDKEY_PAD_4, Numpad4);
+ KEY_CASE(REDKEY_PAD_5, Numpad5);
+ KEY_CASE(REDKEY_PAD_6, Numpad6);
+ KEY_CASE(REDKEY_PAD_PLUS, Add);
+ KEY_CASE(REDKEY_PAD_1, Numpad1);
+ KEY_CASE(REDKEY_PAD_2, Numpad2);
+ KEY_CASE(REDKEY_PAD_3, Numpad3);
+ KEY_CASE(REDKEY_PAD_0, Numpad0);
+ KEY_CASE(REDKEY_PAD_POINT, Decimal);
+
+ KEY_CASE(REDKEY_EUROPEAN, OEM_102);
+ KEY_CASE(REDKEY_F11, F11);
+ KEY_CASE(REDKEY_F12, F12);
+
+ KEY_CASE(REDKEY_JAPANESE_HIRAGANA_KATAKANA, Kana);
+ KEY_CASE(REDKEY_JAPANESE_BACKSLASH, ABNT_C1);
+ KEY_CASE(REDKEY_JAPANESE_HENKAN, Convert);
+ KEY_CASE(REDKEY_JAPANESE_MUHENKAN, NoConvert);
+ KEY_CASE(REDKEY_JAPANESE_YEN, Yen);
+
+ //KEY_CASE(REDKEY_KOREAN_HANGUL_HANJA,
+ //KEY_CASE(REDKEY_KOREAN_HANGUL,
+
+ KEY_CASE(REDKEY_PAD_ENTER, NumpadEnter);
+ KEY_CASE(REDKEY_R_CTRL, RightControl);
+ KEY_CASE(REDKEY_FAKE_L_SHIFT, LeftShift);
+ KEY_CASE(REDKEY_PAD_DIVIDE, Divide);
+ KEY_CASE(REDKEY_FAKE_R_SHIFT, RightShift);
+ KEY_CASE(REDKEY_CTRL_PRINT_SCREEN, SysRq);
+ KEY_CASE(REDKEY_R_ALT, RightAlt);
+ //KEY_CASE(REDKEY_CTRL_BREAK
+ KEY_CASE(REDKEY_HOME, Home);
+ KEY_CASE(REDKEY_UP, ArrowUp);
+ KEY_CASE(REDKEY_PAGEUP, PageUp);
+ KEY_CASE(REDKEY_LEFT, ArrowLeft);
+ KEY_CASE(REDKEY_RIGHT, ArrowRight);
+ KEY_CASE(REDKEY_END, End);
+ KEY_CASE(REDKEY_DOWN, ArrowDown);
+ KEY_CASE(REDKEY_PAGEDOWN, PageDown);
+ KEY_CASE(REDKEY_INSERT, Insert);
+ KEY_CASE(REDKEY_DELETE, Delete);
+ KEY_CASE(REDKEY_LEFT_CMD, LeftWindows);
+ KEY_CASE(REDKEY_RIGHT_CMD, RightWindows);
+ KEY_CASE(REDKEY_MENU, AppMenu);
+ KEY_CASE(REDKEY_PAUSE, Pause);
+ default:
+ return (CEGUI::Key::Scan)0;
+ };
+}
+
+void GUI::on_key_down(RedKey key)
+{
+ CEGUI::Key::Scan scan = red_ket_cegui_scan(key);
+
+ if (scan == (CEGUI::Key::Scan)0) {
+ return;
+ }
+
+ _gui_system->injectKeyDown(scan);
+ conditional_update();
+}
+
+void GUI::on_key_up(RedKey key)
+{
+ CEGUI::Key::Scan scan = red_ket_cegui_scan(key);
+
+ if (scan == (CEGUI::Key::Scan)0) {
+ return;
+ }
+
+ _gui_system->injectKeyUp(scan);
+ conditional_update();
+}
+
+void GUI::on_char(uint32_t ch)
+{
+ _gui_system->injectChar(ch);
+ conditional_update();
+}
+
+void GUI::idle()
+{
+ uint64_t now = Platform::get_monolithic_time();
+ _gui_system->injectTimePulse(float(double(now) - double(_prev_time)) / (1000 * 1000 * 1000));
+ _prev_time = now;
+ conditional_update();
+}
+
+bool GUI::message_box(MessageType type, const char *text, const ButtonsList& buttons,
+ BoxResponse* _response_handler)
+{
+ if (!_dialog) {
+ set_dialog(new MessageDialog(*this));
+ }
+ return _dialog->message_box(type, text, buttons, _response_handler);
+}
+
diff --git a/client/gui/gui.h b/client/gui/gui.h
new file mode 100644
index 00000000..2e505b02
--- /dev/null
+++ b/client/gui/gui.h
@@ -0,0 +1,120 @@
+#ifndef _H_GUI
+#define _H_GUI
+
+#include "softrenderer.h"
+#include "screen_layer.h"
+#include "inputs_handler.h"
+#include "application.h"
+
+class RedPixmapCairo;
+
+class GUI : public ScreenLayer, public KeyHandler {
+public:
+ class Dialog;
+ class Tab;
+ class TabFactory;
+
+ typedef std::list<TabFactory*> TabFactorys;
+
+ GUI(Application& app, Application::State state);
+ virtual ~GUI();
+
+ void set_screen(RedScreen* screen); //show and hide
+
+ Application& get_application() { return _app;}
+ CEGUI::System& gui_system() { return *_gui_system;}
+
+ void set_state(Application::State state);
+ bool is_visible() { return !!_dialog;}
+ bool prepare_dialog();
+ bool is_disconnect_allowed() { return _app.is_disconnect_allowed();}
+
+ virtual bool pointer_test(int x, int y) { return contains_point(x, y);}
+ virtual void on_pointer_enter(int x, int y, unsigned int buttons_state);
+ virtual void on_pointer_leave();
+ virtual void on_pointer_motion(int x, int y, unsigned int buttons_state);
+ virtual void on_mouse_button_press(int button, int buttons_state);
+ virtual void on_mouse_button_release(int button, int buttons_state);
+
+ virtual void on_key_down(RedKey key);
+ virtual void on_key_up(RedKey key);
+ virtual void on_char(uint32_t ch);
+ virtual bool permit_focus_loss() { return false;}
+
+ void idle();
+
+ virtual void copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc);
+ virtual void on_size_changed();
+
+ void register_tab_factory(TabFactory& factory);
+ void unregister_tab_factory(TabFactory& factory);
+
+ class BoxResponse {
+ public:
+ virtual ~BoxResponse() {}
+ virtual void response(int response) = 0;
+ virtual void aborted() = 0;
+ };
+
+ enum MessageType {
+ QUESTION,
+ INFO,
+ WARNINNG,
+ ERROR,
+ };
+
+ struct ButtonInfo {
+ int id;
+ const char *text;
+ };
+
+ typedef std::vector<ButtonInfo> ButtonsList;
+ bool message_box(MessageType type, const char *text, const ButtonsList& buttons,
+ BoxResponse* _response_handler);
+
+private:
+ TabFactorys& get_factoris() { return _tab_factorys;}
+
+ void create_dialog();
+ void detach();
+ void update_layer_area();
+ void init_cegui();
+ void conditional_update();
+ void set_dialog(Dialog* dialog);
+
+private:
+ Application& _app;
+ Application::State _state;
+ RedPixmapCairo* _pixmap;
+ CEGUI::SoftRenderer* _renderer;
+ CEGUI::System* _gui_system;
+ Dialog* _dialog;
+ uint64_t _prev_time;
+ TabFactorys _tab_factorys;
+
+ friend class Dialog;
+};
+
+class GUI::Tab {
+public:
+ virtual ~Tab() {}
+
+ virtual CEGUI::Window& get_root_window() = 0;
+ virtual const std::string& get_name() = 0;
+};
+
+class GUI::TabFactory {
+public:
+ TabFactory() : _order (-1) {}
+ TabFactory(int order) : _order (order) {}
+
+ virtual ~TabFactory() {}
+ virtual Tab* create_tab(bool connected, int width, int hight) = 0;
+ int get_order() { return _order;}
+
+private:
+ int _order;
+};
+
+#endif
+
diff --git a/client/gui/resource_provider.cpp b/client/gui/resource_provider.cpp
new file mode 100644
index 00000000..47f86a43
--- /dev/null
+++ b/client/gui/resource_provider.cpp
@@ -0,0 +1,128 @@
+#include "common.h"
+
+#include "resource_provider.h"
+#include "debug.h"
+#include "utils.h"
+
+#include "CEGUIExceptions.h"
+
+#include "taharez_look.scheme.c"
+#include "taharez_look.imageset.c"
+#include "taharez_look.tga.c"
+#include "commonwealth-10.font.c"
+#include "commonv2c.ttf.c"
+#include "taharez_look.looknfeel.c"
+#include "dejavu_sans-10.font.c"
+#include "dejavu_sans.ttf.c"
+
+//(echo "const unsigned char <struct name>[] =
+//{"; od -txC -v <in file name> | sed -e "s/^[0-9]*//" -e s"/ \([0-9a-f][0-9a-f]\)/0x\1,/g" -e"\$d"
+//| sed -e"\$s/,$/};/") > <out file name>.c
+
+void CEGUIResourceProvider::loadRawDataContainer(const CEGUI::String &filename,
+ CEGUI::RawDataContainer &output,
+ const CEGUI::String &resourceGroup)
+{
+ DBG(0, "%s", filename.c_str());
+ if (strcmp(filename.c_str(), "TaharezLook.scheme") == 0) {
+ DBG(0, "size %d", sizeof(taharez_look_schem));
+ output.setData((CEGUI::uint8*)taharez_look_schem);
+ output.setSize(sizeof(taharez_look_schem));
+ return;
+ }
+
+ if (strcmp(filename.c_str(), "TaharezLook.imageset") == 0) {
+ DBG(0, "size %d", sizeof(taharez_look_imageset));
+ output.setData((CEGUI::uint8*)taharez_look_imageset);
+ output.setSize(sizeof(taharez_look_imageset));
+ return;
+ }
+
+ if (strcmp(filename.c_str(), "TaharezLook.tga") == 0) {
+ DBG(0, "size %d", sizeof(taharez_look_tga));
+ output.setData((CEGUI::uint8*)taharez_look_tga);
+ output.setSize(sizeof(taharez_look_tga));
+ return;
+ }
+
+ if (strcmp(filename.c_str(), "Commonwealth-10.font") == 0) {
+ DBG(0, "size %d", sizeof(commonwealth_10_font));
+ output.setData((CEGUI::uint8*)commonwealth_10_font);
+ output.setSize(sizeof(commonwealth_10_font));
+ return;
+ }
+
+ if (strcmp(filename.c_str(), "Commonv2c.ttf") == 0) {
+ DBG(0, "size %d", sizeof(commonv2c_ttf));
+ output.setData((CEGUI::uint8*)commonv2c_ttf);
+ output.setSize(sizeof(commonv2c_ttf));
+ return;
+ }
+
+ if (strcmp(filename.c_str(), "TaharezLook.looknfeel") == 0) {
+ DBG(0, "size %d", sizeof(taharez_look_looknfeel));
+ output.setData((CEGUI::uint8*)taharez_look_looknfeel);
+ output.setSize(sizeof(taharez_look_looknfeel));
+ return;
+ }
+
+ if (strcmp(filename.c_str(), "DejaVuSans-10.font") == 0) {
+ DBG(0, "size %d", sizeof(dejavu_sans_10_font));
+ output.setData((CEGUI::uint8*)dejavu_sans_10_font);
+ output.setSize(sizeof(dejavu_sans_10_font));
+ return;
+ }
+
+ if (strcmp(filename.c_str(), "DejaVuSans.ttf") == 0) {
+ DBG(0, "size %d", sizeof(dejavu_sans_ttf));
+ output.setData((CEGUI::uint8*)dejavu_sans_ttf);
+ output.setSize(sizeof(dejavu_sans_ttf));
+ return;
+ }
+
+ throw CEGUI::GenericException("failed");
+}
+
+void CEGUIResourceProvider::unloadRawDataContainer(CEGUI::RawDataContainer& data)
+{
+ data.setData(NULL);
+ data.setSize(0);
+}
+
+struct ResString{
+ int id;
+ const char* str;
+} res_strings[] = {
+ {STR_MESG_MISSING_HOST_NAME, "Missing host name"},
+ {STR_MESG_INVALID_PORT, "Invalid port"},
+ {STR_MESG_INVALID_SPORT, "Invalid sport"},
+ {STR_MESG_MISSING_PORT, "Missing port"},
+ {STR_MESG_CONNECTING, "Connecting to"},
+ {STR_BUTTON_OK, "OK"},
+ {STR_BUTTON_CANCEL, "Cancel"},
+ {STR_BUTTON_CONNECT, "Connect"},
+ {STR_BUTTON_QUIT, "Quit"},
+ {STR_BUTTON_CLOSE, "Close"},
+ {STR_BUTTON_DISCONNECT, "Disconnect"},
+ {STR_BUTTON_OPTIONS, "Options"},
+ {STR_BUTTON_BACK, "Back"},
+ {STR_LABEL_HOST, "Host"},
+ {STR_LABEL_PORT, "Port"},
+ {STR_LABEL_SPORT, "Secore port"},
+ {STR_LABEL_PASSWORD, "Password"},
+ {0, NULL},
+};
+
+const char* res_get_string(int id)
+{
+ ResString *string;
+
+ for (string = res_strings; string->str; string++) {
+ if (string->id == id) {
+ return string->str;
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/client/gui/resource_provider.h b/client/gui/resource_provider.h
new file mode 100644
index 00000000..1443abe4
--- /dev/null
+++ b/client/gui/resource_provider.h
@@ -0,0 +1,40 @@
+#ifndef _H_RESOURCE_PROVIDER
+#define _H_RESOURCE_PROVIDER
+
+#include "CEGUIDefaultResourceProvider.h"
+
+class CEGUIResourceProvider: public CEGUI::ResourceProvider {
+public:
+ virtual void loadRawDataContainer(const CEGUI::String &filename,
+ CEGUI::RawDataContainer &output,
+ const CEGUI::String &resourceGroup);
+
+ virtual void unloadRawDataContainer(CEGUI::RawDataContainer& data);
+};
+
+enum {
+ STR_INVALID,
+ STR_MESG_MISSING_HOST_NAME,
+ STR_MESG_INVALID_PORT,
+ STR_MESG_INVALID_SPORT,
+ STR_MESG_MISSING_PORT,
+ STR_MESG_CONNECTING,
+ STR_BUTTON_OK,
+ STR_BUTTON_CANCEL,
+ STR_BUTTON_CONNECT,
+ STR_BUTTON_QUIT,
+ STR_BUTTON_CLOSE,
+ STR_BUTTON_DISCONNECT,
+ STR_BUTTON_OPTIONS,
+ STR_BUTTON_BACK,
+ STR_LABEL_HOST,
+ STR_LABEL_PORT,
+ STR_LABEL_SPORT,
+ STR_LABEL_PASSWORD,
+};
+
+//todo: move to x11/res.cpp and make x11/res.cpp cross-platform
+const char* res_get_string(int id);
+
+#endif
+
diff --git a/client/gui/softrenderer.cpp b/client/gui/softrenderer.cpp
index 9e08f7a5..87fffb8b 100644
--- a/client/gui/softrenderer.cpp
+++ b/client/gui/softrenderer.cpp
@@ -64,19 +64,23 @@ void SoftRenderer::setupImageCodec()
#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;
@@ -86,14 +90,12 @@ void SoftRenderer::setupImageCodec()
#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
@@ -369,4 +371,3 @@ uint SoftRenderer::getVertScreenDPI() const
}
-
diff --git a/client/gui/softrenderer.h b/client/gui/softrenderer.h
index 939eb38b..9fc1a29e 100644
--- a/client/gui/softrenderer.h
+++ b/client/gui/softrenderer.h
@@ -128,4 +128,3 @@ namespace CEGUI
#endif
-
diff --git a/client/platform.h b/client/platform.h
index c32b8634..07777c07 100644
--- a/client/platform.h
+++ b/client/platform.h
@@ -40,6 +40,7 @@ public:
static void get_temp_dir(std::string& path);
static uint64_t get_process_id();
static uint64_t get_thread_id();
+ static void error_beep();
static const MonitorsList& init_monitors();
static void destroy_monitors();
diff --git a/client/red_channel.cpp b/client/red_channel.cpp
index cfd47057..c7dce015 100644
--- a/client/red_channel.cpp
+++ b/client/red_channel.cpp
@@ -401,7 +401,8 @@ void RedChannel::run()
_client.get_port(),
_client.get_sport());
RedChannelBase::connect(con_options, _client.get_connection_id(),
- _client.get_host(), _client.get_password());
+ _client.get_host().c_str(),
+ _client.get_password().c_str());
on_connect();
set_state(CONNECTED_STATE);
_loop.add_socket(*this);
diff --git a/client/red_client.cpp b/client/red_client.cpp
index 8fcb81d6..e040f63f 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -274,9 +274,12 @@ public:
RedClient::RedClient(Application& application)
: RedChannel(*this, RED_CHANNEL_MAIN, 0, new MainChannelLoop(*this))
, _application (application)
+ , _port (-1)
+ , _sport (-1)
, _connection_id (0)
, _mouse_mode (RED_MOUSE_MODE_SERVER)
, _notify_disconnect (false)
+ , _auto_display_res (false)
, _aborting (false)
, _agent_connected (false)
, _agent_mon_config_sent (false)
@@ -326,22 +329,7 @@ RedClient::~RedClient()
delete _agent_msg;
}
-void RedClient::init(const char* host, int port, int sport, const char *password,
- bool auto_display_res)
-{
- _host = host;
- _port = port;
- _sport = sport;
- _auto_display_res = auto_display_res;
-
- if (password != NULL) {
- _password = password;
- } else {
- _password = "";
- }
-}
-
-void RedClient::set_target(const char* host, uint16_t port, uint16_t sport)
+void RedClient::set_target(const std::string& host, int port, int sport)
{
_port = port;
_sport = sport;
diff --git a/client/red_client.h b/client/red_client.h
index fde958f2..a98d2d2f 100644
--- a/client/red_client.h
+++ b/client/red_client.h
@@ -131,8 +131,6 @@ public:
RedClient(Application& application);
~RedClient();
- void init(const char* host, int port, int sport, const char *password, bool auto_display_res);
-
void register_channel_factory(ChannelFactory& factory);
virtual void connect();
@@ -143,9 +141,11 @@ public:
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();}
- const char* get_host() { return _host.c_str();}
+ void set_target(const std::string&, int port, int sport);
+ void set_password(const std::string& password) { _password = password;}
+ void set_auto_display_res(bool auto_display_res) { _auto_display_res = auto_display_res;}
+ const std::string& get_password() { return _password;}
+ const std::string& get_host() { return _host;}
int get_port() { return _port;}
int get_sport() { return _sport;}
virtual uint32_t get_connection_id() { return _connection_id;}
@@ -202,10 +202,10 @@ private:
private:
Application& _application;
- std::string _password;
std::string _host;
int _port;
int _sport;
+ std::string _password;
uint32_t _connection_id;
uint32_t _mouse_mode;
Mutex _notify_lock;
diff --git a/client/screen.h b/client/screen.h
index 5952fe81..c07d5419 100644
--- a/client/screen.h
+++ b/client/screen.h
@@ -37,7 +37,9 @@ class RedScreen;
enum {
SCREEN_LAYER_DISPLAY,
SCREEN_LAYER_CURSOR,
+ SCREEN_LAYER_GUI_BARIER,
SCREEN_LAYER_GUI,
+ SCREEN_LAYER_INFO,
};
class UpdateTimer: public Timer {
diff --git a/client/utils.cpp b/client/utils.cpp
index 29201743..c27aa361 100644
--- a/client/utils.cpp
+++ b/client/utils.cpp
@@ -37,3 +37,14 @@ void wstring_printf(std::wstring& str, const wchar_t* format, ...)
va_end(ap);
}
+int str_to_port(const char *str)
+{
+ long port;
+ char *endptr;
+ port = strtol(str, &endptr, 0);
+ if (endptr != str + strlen(str) || port < 0 || port > 0xffff) {
+ return -1;
+ }
+ return port;
+}
+
diff --git a/client/utils.h b/client/utils.h
index 4be75281..d4163b87 100644
--- a/client/utils.h
+++ b/client/utils.h
@@ -98,6 +98,8 @@ static inline void set_bit_be(const void* addr, int bit)
((uint8_t*)addr)[bit >> 3] |= (0x80 >> (bit & 0x07));
}
+int str_to_port(const char *str);
+
void string_vprintf(std::string& str, const char* format, va_list ap);
void string_printf(std::string& str, const char *format, ...);
void wstring_vprintf(std::wstring& str, const wchar_t* format, va_list ap);
diff --git a/client/windows/platform.cpp b/client/windows/platform.cpp
index 6d5deba5..11f13266 100644
--- a/client/windows/platform.cpp
+++ b/client/windows/platform.cpp
@@ -218,6 +218,11 @@ uint64_t Platform::get_thread_id()
return GetCurrentThreadId();
}
+void Platform::error_beep()
+{
+ MessageBeep(MB_ICONERROR);
+}
+
class WinMonitor: public Monitor {
public:
WinMonitor(int id, const wchar_t* name, const wchar_t* string);
diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj
index 2741ae57..2f97d378 100644
--- a/client/windows/redc.vcproj
+++ b/client/windows/redc.vcproj
@@ -241,6 +241,10 @@
>
</File>
<File
+ RelativePath="..\gui\gui.cpp"
+ >
+ </File>
+ <File
RelativePath="..\hot_keys.cpp"
>
</File>
@@ -371,6 +375,10 @@
>
</File>
<File
+ RelativePath="..\gui\resource_provider.cpp"
+ >
+ </File>
+ <File
RelativePath="..\rop3.cpp"
>
</File>
@@ -481,6 +489,10 @@
>
</File>
<File
+ RelativePath="..\gui\gui.h"
+ >
+ </File>
+ <File
RelativePath="..\hot_keys.h"
>
</File>
@@ -569,6 +581,10 @@
>
</File>
<File
+ RelativePath="..\gui\resource_provider.h"
+ >
+ </File>
+ <File
RelativePath="..\screen.h"
>
</File>
diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am
index 072548db..12039f0f 100644
--- a/client/x11/Makefile.am
+++ b/client/x11/Makefile.am
@@ -107,6 +107,10 @@ RED_COMMON_SRCS = \
$(top_srcdir)/client/gui/softrenderer.cpp \
$(top_srcdir)/client/gui/softtexture.h \
$(top_srcdir)/client/gui/softtexture.cpp \
+ $(top_srcdir)/client/gui/resource_provider.h \
+ $(top_srcdir)/client/gui/resource_provider.cpp \
+ $(top_srcdir)/client/gui/gui.h \
+ $(top_srcdir)/client/gui/gui.cpp \
$(NULL)
bin_PROGRAMS = spicec
diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index d13c9fe6..1a98e2ed 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -249,6 +249,15 @@ uint64_t Platform::get_thread_id()
return uint64_t(syscall(SYS_gettid));
}
+void Platform::error_beep()
+{
+ if (!x_display) {
+ return;
+ }
+
+ XBell(x_display, 0);
+}
+
void Platform::msleep(unsigned int millisec)
{
usleep(millisec * 1000);