client: Remove client code

The client has been superseded by virt-viewer (
http://virt-manager.org/download/sources/virt-viewer/ ) and is no longer
being maintained.
This commit is contained in:
Christophe Fergeau 2014-11-21 11:01:17 +01:00
parent b532ef0866
commit 1876971442
178 changed files with 1 additions and 104026 deletions

View File

@ -3,10 +3,6 @@ ACLOCAL_AMFLAGS = -I m4
SUBDIRS = spice-common server docs
if SUPPORT_CLIENT
SUBDIRS += client
endif
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = spice-server.pc

13
client/.gitignore vendored
View File

@ -1,13 +0,0 @@
*.la
*.lo
*.loT
*.o
.deps
.libs
Makefile
Makefile.in
generated_demarshallers.cpp
generated_demarshallers1.cpp
generated_marshallers.cpp
generated_marshallers1.cpp
spicec

View File

@ -1,249 +0,0 @@
NULL =
bin_PROGRAMS = spicec
spicec_SOURCES = \
application.cpp \
application.h \
audio_channels.h \
audio_devices.h \
cache.hpp \
canvas.cpp \
canvas.h \
client_net_socket.cpp \
client_net_socket.h \
cmd_line_parser.cpp \
cmd_line_parser.h \
common.h \
controller.cpp \
controller.h \
cursor.cpp \
cursor.h \
cursor_channel.cpp \
cursor_channel.h \
debug.h \
display_channel.cpp \
display_channel.h \
event_sources.h \
foreign_menu.cpp \
foreign_menu.h \
glz_decoded_image.h \
glz_decoder.cpp \
glz_decoder.h \
glz_decoder_config.h \
glz_decoder_window.cpp \
glz_decoder_window.h \
hot_keys.cpp \
hot_keys.h \
icon.h \
inputs_channel.cpp \
inputs_channel.h \
inputs_handler.h \
jpeg_decoder.cpp \
jpeg_decoder.h \
menu.cpp \
menu.h \
mjpeg_decoder.cpp \
mjpeg_decoder.h \
monitor.cpp \
monitor.h \
pixels_source.h \
platform.h \
playback_channel.cpp \
process_loop.cpp \
process_loop.h \
read_write_mutex.h \
record_channel.cpp \
red_canvas_base.h \
red_channel.cpp \
red_channel.h \
red_client.cpp \
red_client.h \
red_drawable.h \
red_key.h \
red_peer.cpp \
red_peer.h \
red_pixmap.h \
red_pixmap_sw.h \
red_sw_canvas.cpp \
red_sw_canvas.h \
red_types.h \
red_window.h \
screen.cpp \
screen.h \
screen_layer.cpp \
screen_layer.h \
shared_cache.hpp \
threads.cpp \
threads.h \
utils.cpp \
utils.h \
zlib_decoder.cpp \
zlib_decoder.h \
$(BUILT_SOURCES) \
$(NULL)
if OS_WIN32
spicec_SOURCES += \
red_gdi_canvas.cpp \
red_gdi_canvas.h \
red_pixmap_gdi.h \
windows/atomic_count.h \
windows/event_sources_p.cpp \
windows/main.cpp \
windows/my_getopt.cpp \
windows/named_pipe.cpp \
windows/named_pipe.h \
windows/pixels_source.cpp \
windows/pixels_source_p.h \
windows/platform.cpp \
windows/platform_utils.cpp \
windows/platform_utils.h \
windows/playback.cpp \
windows/playback.h \
windows/record.cpp \
windows/record.h \
windows/red_drawable.cpp \
windows/red_pixmap.cpp \
windows/red_pixmap_gdi.cpp \
windows/red_pixmap_sw.cpp \
windows/red_window.cpp \
windows/red_window_p.h \
windows/resource.h \
windows/stdint.h \
windows/win_platform.h \
$(NULL)
spicec_resource_LDADD = windows/redc.o
windows/redc.o: windows/redc.rc
$(WINDRES) $< -o $@
else
spicec_SOURCES += \
x11/atomic_count.h \
x11/event_sources_p.cpp \
x11/event_sources_p.h \
x11/main.cpp \
x11/named_pipe.cpp \
x11/named_pipe.h \
x11/pixels_source.cpp \
x11/pixels_source_p.h \
x11/platform.cpp \
x11/platform_utils.cpp \
x11/platform_utils.h \
x11/playback.cpp \
x11/playback.h \
x11/record.cpp \
x11/record.h \
x11/red_drawable.cpp \
x11/red_pixmap.cpp \
x11/red_pixmap_sw.cpp \
x11/red_window.cpp \
x11/red_window_p.h \
x11/res.cpp \
x11/res.h \
x11/resource.h \
x11/x_icon.cpp \
x11/x_icon.h \
x11/x_platform.h \
$(NULL)
endif
if OS_WIN32
PLATFORM_INCLUDES=-I$(top_srcdir)/client/windows
else
PLATFORM_INCLUDES=-I$(top_srcdir)/client/x11
endif
if SUPPORT_GUI
spicec_SOURCES += \
gui/gui.cpp \
gui/gui.h \
gui/resource_provider.cpp \
gui/resource_provider.h \
gui/softrenderer.cpp \
gui/softrenderer.h \
gui/softtexture.cpp \
gui/softtexture.h \
$(NULL)
endif
if SUPPORT_GL
spicec_SOURCES += \
red_gl_canvas.cpp \
red_gl_canvas.h \
red_pixmap_gl.h \
$(NULL)
if !OS_WIN32
spicec_SOURCES += x11/red_pixmap_gl.cpp
endif
endif
if SUPPORT_SMARTCARD
spicec_SOURCES += \
smartcard_channel.cpp \
smartcard_channel.h \
$(NULL)
endif
AM_CPPFLAGS = \
-D__STDC_LIMIT_MACROS \
$(PLATFORM_INCLUDES) \
-I$(top_srcdir)/spice-common \
$(ALSA_CFLAGS) \
$(CEGUI_CFLAGS) \
$(CEGUI06_CFLAGS) \
$(CELT051_CFLAGS) \
$(GL_CFLAGS) \
$(MISC_X_CFLAGS) \
$(PIXMAN_CFLAGS) \
$(COMMON_CFLAGS) \
$(SPICE_NONPKGCONFIG_CFLAGS) \
$(SMARTCARD_CFLAGS) \
$(SSL_CFLAGS) \
$(XRANDR_CFLAGS) \
$(XFIXES_CFLAGS) \
$(WARN_CXXFLAGS) \
$(XINERAMA_CFLAGS) \
$(CXIMAGE_CFLAGS) \
$(NULL)
spicec_LDFLAGS = $(SPICEC_STATIC_LINKAGE_BSTATIC)
spicec_LDADD = \
$(top_builddir)/spice-common/common/libspice-common.la \
$(top_builddir)/spice-common/common/libspice-common-client.la \
$(ALSA_LIBS) \
$(CEGUI_LIBS) \
$(CEGUI06_LIBS) \
$(CELT051_LIBS) \
$(GL_LIBS) \
$(JPEG_LIBS) \
$(MISC_X_LIBS) \
$(PIXMAN_LIBS) \
$(SMARTCARD_LIBS) \
$(SPICE_NONPKGCONFIG_LIBS) \
$(SSL_LIBS) \
$(XFIXES_LIBS) \
$(XRANDR_LIBS) \
$(Z_LIBS) \
$(XINERAMA_LIBS) \
$(spicec_resource_LDADD) \
$(NULL)
EXTRA_DIST = \
glz_decode_tmpl.c \
x11/images/red_icon.c \
x11/images/alt_image.c \
gui/commonv2c.ttf.c \
gui/commonwealth-10.font.c \
gui/dejavu_sans-10.font.c \
gui/dejavu_sans.ttf.c \
gui/taharez_look.imageset.c \
gui/taharez_look.looknfeel.c \
gui/taharez_look.scheme.c \
gui/taharez_look.tga.c \
$(NULL)

File diff suppressed because it is too large Load Diff

View File

@ -1,413 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_APPLICATION
#define _H_APPLICATION
#include "common.h"
#include "threads.h"
#include "red_client.h"
#include "red_key.h"
#include "platform.h"
#include "menu.h"
#include "hot_keys.h"
#include "process_loop.h"
#include "foreign_menu.h"
#include "controller.h"
#ifdef USE_SMARTCARD
struct SmartcardOptions;
#endif
class RedScreen;
class Application;
class ScreenLayer;
class InfoLayer;
class InputsHandler;
class Monitor;
class CmdLineParser;
class Menu;
#ifdef USE_GUI
class GUI;
class GUITimer;
class GUIBarrier;
#ifdef GUI_DEMO
class TestTimer;
#endif
#endif // USE_GUI
class ConnectedEvent: public Event {
public:
virtual void response(AbstractProcessLoop& events_loop);
};
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);
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;
SpicePoint size;
SpicePoint position;
};
class MonitorsQuery: public SyncEvent {
public:
MonitorsQuery() {}
virtual void do_response(AbstractProcessLoop& events_loop);
std::vector<MonitorInfo>& get_monitors() {return _monitors;}
private:
std::vector<MonitorInfo> _monitors;
};
class SwitchHostEvent: public Event {
public:
SwitchHostEvent(const char* host, int port, int sport, const char* cert_subject);
virtual void response(AbstractProcessLoop& events_loop);
private:
std::string _host;
int _port;
int _sport;
std::string _cert_subject;
};
enum CanvasOption {
CANVAS_OPTION_INVALID,
CANVAS_OPTION_SW,
#ifdef WIN32
CANVAS_OPTION_GDI,
#endif
#ifdef USE_OPENGL
CANVAS_OPTION_OGL_FBO,
CANVAS_OPTION_OGL_PBUFF,
#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;
typedef std::list<KeyHandler*> KeyHandlersStack;
#ifdef USE_GUI
typedef std::list<GUIBarrier*> GUIBarriers;
#endif // USE_GUI
enum AppMenuItemType {
APP_MENU_ITEM_TYPE_INVALID,
APP_MENU_ITEM_TYPE_FOREIGN,
APP_MENU_ITEM_TYPE_CONTROLLER,
};
typedef struct AppMenuItem {
AppMenuItemType type;
int32_t conn_ref;
uint32_t ext_id;
} AppMenuItem;
typedef std::map<int, AppMenuItem> AppMenuItemMap;
class Application : public ProcessLoop,
public Platform::EventListener,
public Platform::DisplayModeListener,
public ForeignMenuInterface,
public ControllerInterface {
public:
enum State {
DISCONNECTED,
CONNECTING,
CONNECTED,
VISIBILITY,
DISCONECTING,
};
#ifdef USE_GUI
enum GuiMode {
GUI_MODE_FULL,
GUI_MODE_ACTIVE_SESSION,
GUI_MODE_MINIMAL,
};
#endif // USE_GUI
Application();
virtual ~Application();
int run();
void set_key_handler(KeyHandler& handler);
void remove_key_handler(KeyHandler& handler);
void set_mouse_handler(MouseHandler& handler);
void remove_mouse_handler(MouseHandler& handler);
void capture_mouse();
void release_mouse_capture();
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);
void on_mouse_up(int button, int buttons_state);
void on_key_down(RedKey key);
void on_key_up(RedKey key);
void on_char(uint32_t ch);
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_start_running();
virtual void on_app_activated();
virtual void on_app_deactivated();
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);
void enter_full_screen();
void exit_full_screen();
bool toggle_full_screen();
void resize_screen(RedScreen *screen, int width, int height);
void minimize();
void set_title(const std::string& title);
void hide();
void show();
void external_show();
void connect();
void switch_host(const std::string& host, int port, int sport, const std::string& cert_subject);
#ifdef USE_SMARTCARD
void enable_smartcard(bool enable);
#endif
const PeerConnectionOptMap& get_con_opt_map() {return _peer_con_opt;}
const RedPeer::HostAuthOptions& get_host_auth_opt() { return _host_auth_opt;}
const std::string& get_connection_ciphers() { return _con_ciphers;}
uint32_t get_mouse_mode();
const std::vector<int>& get_canvas_types() { return _canvas_types;}
Menu* get_app_menu();
virtual void do_command(int command);
int get_foreign_menu_item_id(int32_t opaque_conn_ref, uint32_t msg_id);
void clear_menu_items(int32_t opaque_conn_ref);
void remove_menu_item(int item_id);
void update_menu();
//controller interface begin
void set_auto_display_res(bool auto_display_res);
bool connect(const std::string& host, int port, int sport, const std::string& password);
void disconnect();
void quit();
void show_me(bool full_screen);
void hide_me();
void set_hotkeys(const std::string& hotkeys);
void set_default_hotkeys(void);
int get_controller_menu_item_id(int32_t opaque_conn_ref, uint32_t msg_id);
void set_menu(Menu* menu);
void delete_menu();
void beep();
#ifdef USE_GUI
bool is_disconnect_allowed();
void hide_gui();
#endif
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
#ifdef USE_SMARTCARD
const SmartcardOptions* get_smartcard_options() const {
return _smartcard_options;
}
#endif
static int main(int argc, char** argv, const char* version_str);
private:
bool set_channels_security(CmdLineParser& parser, bool on, char *val, const char* arg0);
bool set_channels_security(int port, int sport);
bool set_connection_ciphers(const char* ciphers, const char* arg0);
bool set_ca_file(const char* ca_file, const char* arg0);
bool set_host_cert_subject(const char* subject, const char* arg0);
bool set_enable_channels(CmdLineParser& parser, bool enable, char *val, const char* arg0);
bool set_canvas_option(CmdLineParser& parser, char *val, const char* arg0);
bool set_disabled_display_effects(CmdLineParser& parser, char *val, const char* arg0,
DisplaySetting& disp_setting);
void on_cmd_line_invalid_arg(const char* arg0, const char* what, const char* val);
bool process_cmd_line(int argc, char** argv, bool& full_screen);
void register_channels();
void abort();
void init_menu();
void unpress_all();
bool release_capture();
bool do_connect();
bool do_disconnect();
void set_state(State);
void restore_screens_size();
Monitor* find_monitor(int id);
Monitor* get_monitor(int id);
void init_monitors();
void destroy_monitors();
void assign_monitors();
void restore_monitors();
void prepare_monitors(std::vector<SpicePoint> *sizes);
void rearrange_monitors(bool force_capture,
bool enter_full_screen,
RedScreen* screen = NULL,
std::vector<SpicePoint> *sizes = NULL);
void position_screens();
void show_full_screen();
void send_key_down(RedKey key);
void send_key_up(RedKey key);
void send_alt_ctl_del();
void send_ctrl_alt_end();
void send_command_hotkey(int command);
void send_hotkey_key_set(const HotkeySet& key_set);
void menu_item_callback(unsigned int item_id);
int get_menu_item_id(AppMenuItemType type, int32_t conn_ref, uint32_t ext_id);
int get_hotkeys_command();
bool is_key_set_pressed(const HotkeySet& key_set);
void do_on_key_up(RedKey key);
void __remove_key_handler(KeyHandler& handler);
void show_info_layer();
void hide_info_layer();
#ifdef USE_GUI
void attach_gui_barriers();
void detach_gui_barriers();
void show_gui();
void create_gui_barrier(RedScreen& screen, int id);
void destroyed_gui_barrier(int id);
void destroyed_gui_barriers();
#endif // USE_GUI
// 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);
void sync_keyboard_modifiers();
static void init_logger();
static void init_globals();
static void init_platform_globals();
static void cleanup_platform_globals();
static void cleanup_globals();
void init_remainder();
friend class DisconnectedEvent;
friend class ConnectionErrorEvent;
friend class MonitorsQuery;
friend class AutoAbort;
friend class StickyKeyTimer;
private:
RedClient _client;
PeerConnectionOptMap _peer_con_opt;
RedPeer::HostAuthOptions _host_auth_opt;
std::string _con_ciphers;
std::vector<bool> _enabled_channels;
std::vector<RedScreen*> _screens;
RedScreen* _main_screen;
bool _active;
bool _full_screen;
bool _changing_screens;
bool _out_of_sync;
int _exit_code;
RedScreen* _active_screen;
bool _keyboard_state[REDKEY_NUM_KEYS];
int _num_keys_pressed;
HotKeys _hot_keys;
CommandsMap _commands_map;
std::auto_ptr<InfoLayer> _info_layer;
KeyHandler* _key_handler;
KeyHandlersStack _key_handlers;
MouseHandler* _mouse_handler;
const MonitorsList* _monitors;
std::string _title;
bool _sys_key_intercept_mode;
StickyInfo _sticky_info;
std::vector<int> _canvas_types;
AutoRef<Menu> _app_menu;
AutoRef<ForeignMenu> _foreign_menu;
bool _enable_controller;
AutoRef<Controller> _controller;
AppMenuItemMap _app_menu_items;
#ifdef USE_GUI
std::auto_ptr<GUI> _gui;
AutoRef<GUITimer> _gui_timer;
GUIBarriers _gui_barriers;
GuiMode _gui_mode;
#ifdef GUI_DEMO
AutoRef<TestTimer> _gui_test_timer;
#endif
#endif // USE_GUI
bool _during_host_switch;
State _state;
#ifdef USE_SMARTCARD
SmartcardOptions* _smartcard_options;
#endif
};
#endif

View File

@ -1,107 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_AUDIO_CHANNELS
#define _H_AUDIO_CHANNELS
#include "common/snd_codec.h"
#include "red_channel.h"
#include "debug.h"
class ChannelFactory;
class WavePlaybackAbstract;
class WaveRecordAbstract;
class RecordSamplesMessage;
class PlaybackChannel: public RedChannel {
public:
PlaybackChannel(RedClient& client, uint32_t id);
~PlaybackChannel(void);
bool abort(void);
static ChannelFactory& Factory();
protected:
virtual void on_disconnect();
private:
void handle_mode(RedPeer::InMessage* message);
void handle_start(RedPeer::InMessage* message);
void handle_stop(RedPeer::InMessage* message);
void handle_raw_data(RedPeer::InMessage* message);
void handle_compressed_data(RedPeer::InMessage* message);
void null_handler(RedPeer::InMessage* message);
void disable();
void set_data_handler();
void clear();
private:
WavePlaybackAbstract* _wave_player;
uint32_t _mode;
uint32_t _frame_bytes;
SndCodec _codec;
bool _playing;
uint32_t _frame_count;
};
class RecordChannel: public RedChannel, private Platform::RecordClient {
public:
RecordChannel(RedClient& client, uint32_t id);
~RecordChannel(void);
bool abort(void);
static ChannelFactory& Factory();
protected:
virtual void on_disconnect();
private:
void handle_start(RedPeer::InMessage* message);
void handle_stop(RedPeer::InMessage* message);
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 set_desired_mode(int frequency);
void send_record_mode();
void send_start_mark();
void release_message(RecordSamplesMessage *message);
RecordSamplesMessage * get_message();
void clear();
private:
WaveRecordAbstract* _wave_recorder;
Mutex _messages_lock;
std::list<RecordSamplesMessage *> _messages;
int _mode;
SndCodec _codec;
uint32_t _frame_bytes;
uint8_t compressed_buf[SND_CODEC_MAX_COMPRESSED_BYTES];
friend class RecordSamplesMessage;
};
#endif

View File

@ -1,43 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_AUDIO_DEVICES
#define _H_AUDIO_DEVICES
class WavePlaybackAbstract {
public:
WavePlaybackAbstract() {}
virtual ~WavePlaybackAbstract() {}
virtual bool write(uint8_t* frame) = 0;
virtual bool abort() = 0;
virtual void stop() = 0;
virtual uint32_t get_delay_ms() = 0;
};
class WaveRecordAbstract {
public:
WaveRecordAbstract() {}
virtual ~WaveRecordAbstract() {}
virtual void start() = 0;
virtual void stop() = 0;
virtual bool abort() = 0;
};
#endif

View File

@ -1,121 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CACHE
#define _H_CACHE
#include "utils.h"
/*class Cache::Treat {
T* get(T*);
void release(T*);
const char* name();
};*/
template <class T, class Treat, int HASH_SIZE, class Base = EmptyBase>
class Cache : public Base {
public:
Cache()
{
memset(_hash, 0, sizeof(_hash));
}
~Cache()
{
clear();
}
void add(uint64_t id, T* data)
{
Item** item = &_hash[key(id)];
while (*item) {
if ((*item)->id == id) {
spice_printerr("%s id %" PRIu64 ", double insert", Treat::name(), id);
return;
}
item = &(*item)->next;
}
*item = new Item(id, data);
}
T* get(uint64_t id)
{
Item* item = _hash[key(id)];
while (item && item->id != id) {
item = item->next;
}
if (!item) {
THROW("%s id %" PRIu64 ", not found", Treat::name(), id);
}
return Treat::get(item->data);
}
void remove(uint64_t id)
{
Item** item = &_hash[key(id)];
while (*item) {
if ((*item)->id == id) {
Item *rm_item = *item;
*item = rm_item->next;
delete rm_item;
return;
}
item = &(*item)->next;
}
THROW("%s id %" PRIu64 ", not found", Treat::name(), id);
}
void clear()
{
for (int i = 0; i < HASH_SIZE; i++) {
while (_hash[i]) {
Item *item = _hash[i];
_hash[i] = item->next;
delete item;
}
}
}
private:
inline uint32_t key(uint64_t id) {return uint32_t(id) % HASH_SIZE;}
private:
class Item {
public:
Item(uint64_t in_id, T* data)
: id (in_id)
, next (NULL)
, data (Treat::get(data)) {}
~Item()
{
Treat::release(data);
}
uint64_t id;
Item* next;
T* data;
};
Item* _hash[HASH_SIZE];
};
#endif

View File

@ -1,186 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "canvas.h"
#include "utils.h"
#include "debug.h"
static SpiceCanvas* surfaces_cache_op_get(SpiceImageSurfaces *surfaces, uint32_t surface_id)
{
SurfacesCache* surfaces_cache = static_cast<SurfacesCache*>(surfaces);
if (!surfaces_cache->exist(surface_id)) {
return NULL;
}
return (*surfaces_cache)[surface_id]->get_internal_canvas();
}
SurfacesCache::SurfacesCache()
{
static SpiceImageSurfacesOps surfaces_ops = {
surfaces_cache_op_get,
};
ops = &surfaces_ops;
}
bool SurfacesCache::exist(uint32_t surface_id)
{
return (this->count(surface_id) != 0);
}
Canvas::Canvas(PixmapCache& pixmap_cache, PaletteCache& palette_cache,
GlzDecoderWindow &glz_decoder_window, SurfacesCache &csurfaces)
: _canvas (NULL)
, _pixmap_cache (pixmap_cache)
, _palette_cache (palette_cache)
, _glz_decoder(glz_decoder_window, _glz_handler, _glz_debug)
, _surfaces_cache(csurfaces)
{
}
Canvas::~Canvas()
{
/* _canvas is both set and destroyed by derived class */
}
void Canvas::clear()
{
if (_canvas) {
_canvas->ops->clear(_canvas);
}
}
void Canvas::begin_draw(SpiceMsgDisplayBase& base, int size, size_t min_size)
{
}
void Canvas::draw_fill(SpiceMsgDisplayDrawFill& fill, int size)
{
begin_draw(fill.base, size, sizeof(SpiceMsgDisplayDrawFill));
_canvas->ops->draw_fill(_canvas, &fill.base.box, &fill.base.clip, &fill.data);
touched_bbox(&fill.base.box);
}
void Canvas::draw_text(SpiceMsgDisplayDrawText& text, int size)
{
begin_draw(text.base, size, sizeof(SpiceMsgDisplayDrawText));
_canvas->ops->draw_text(_canvas, &text.base.box, &text.base.clip, &text.data);
touched_bbox(&text.base.box);
}
void Canvas::draw_opaque(SpiceMsgDisplayDrawOpaque& opaque, int size)
{
begin_draw(opaque.base, size, sizeof(SpiceMsgDisplayDrawOpaque));
_canvas->ops->draw_opaque(_canvas, &opaque.base.box, &opaque.base.clip, &opaque.data);
touched_bbox(&opaque.base.box);
}
void Canvas::draw_copy(SpiceMsgDisplayDrawCopy& copy, int size)
{
begin_draw(copy.base, size, sizeof(SpiceMsgDisplayDrawCopy));
_canvas->ops->draw_copy(_canvas, &copy.base.box, &copy.base.clip, &copy.data);
touched_bbox(&copy.base.box);
}
void Canvas::draw_transparent(SpiceMsgDisplayDrawTransparent& transparent, int size)
{
begin_draw(transparent.base, size, sizeof(SpiceMsgDisplayDrawTransparent));
_canvas->ops->draw_transparent(_canvas, &transparent.base.box, &transparent.base.clip, &transparent.data);
touched_bbox(&transparent.base.box);
}
void Canvas::draw_alpha_blend(SpiceMsgDisplayDrawAlphaBlend& alpha_blend, int size)
{
begin_draw(alpha_blend.base, size, sizeof(SpiceMsgDisplayDrawAlphaBlend));
_canvas->ops->draw_alpha_blend(_canvas, &alpha_blend.base.box, &alpha_blend.base.clip, &alpha_blend.data);
touched_bbox(&alpha_blend.base.box);
}
void Canvas::draw_composite(SpiceMsgDisplayDrawComposite& composite, int size)
{
begin_draw(composite.base, size, sizeof(SpiceMsgDisplayDrawComposite));
_canvas->ops->draw_composite(_canvas, &composite.base.box, &composite.base.clip, &composite.data);
touched_bbox(&composite.base.box);
}
void Canvas::copy_bits(SpiceMsgDisplayCopyBits& copy, int size)
{
begin_draw(copy.base, size, sizeof(SpiceMsgDisplayCopyBits));
_canvas->ops->copy_bits(_canvas, &copy.base.box, &copy.base.clip, &copy.src_pos);
touched_bbox(&copy.base.box);
}
void Canvas::draw_blend(SpiceMsgDisplayDrawBlend& blend, int size)
{
begin_draw(blend.base, size, sizeof(SpiceMsgDisplayDrawBlend));
_canvas->ops->draw_blend(_canvas, &blend.base.box, &blend.base.clip, &blend.data);
touched_bbox(&blend.base.box);
}
void Canvas::draw_blackness(SpiceMsgDisplayDrawBlackness& blackness, int size)
{
begin_draw(blackness.base, size, sizeof(SpiceMsgDisplayDrawBlackness));
_canvas->ops->draw_blackness(_canvas, &blackness.base.box, &blackness.base.clip, &blackness.data);
touched_bbox(&blackness.base.box);
}
void Canvas::draw_whiteness(SpiceMsgDisplayDrawWhiteness& whiteness, int size)
{
begin_draw(whiteness.base, size, sizeof(SpiceMsgDisplayDrawWhiteness));
_canvas->ops->draw_whiteness(_canvas, &whiteness.base.box, &whiteness.base.clip, &whiteness.data);
touched_bbox(&whiteness.base.box);
}
void Canvas::draw_invers(SpiceMsgDisplayDrawInvers& invers, int size)
{
begin_draw(invers.base, size, sizeof(SpiceMsgDisplayDrawInvers));
_canvas->ops->draw_invers(_canvas, &invers.base.box, &invers.base.clip, &invers.data);
touched_bbox(&invers.base.box);
}
void Canvas::draw_rop3(SpiceMsgDisplayDrawRop3& rop3, int size)
{
begin_draw(rop3.base, size, sizeof(SpiceMsgDisplayDrawRop3));
_canvas->ops->draw_rop3(_canvas, &rop3.base.box, &rop3.base.clip, &rop3.data);
touched_bbox(&rop3.base.box);
}
void Canvas::draw_stroke(SpiceMsgDisplayDrawStroke& stroke, int size)
{
begin_draw(stroke.base, size, sizeof(SpiceMsgDisplayDrawStroke));
_canvas->ops->draw_stroke(_canvas, &stroke.base.box, &stroke.base.clip, &stroke.data);
touched_bbox(&stroke.base.box);
}
void Canvas::put_image(
#ifdef WIN32
HDC dc,
#endif
const PixmapHeader& image, const SpiceRect& dest, const QRegion* clip)
{
_canvas->ops->put_image(_canvas,
#ifdef WIN32
dc,
#endif
&dest, image.data, image.width, image.height, image.stride,
clip);
touched_bbox(&dest);
}

View File

@ -1,352 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CANVAS
#define _H_CANVAS
#include <map>
#include "common/region.h"
#include "common/messages.h"
#include "common/canvas_utils.h"
#include "common.h"
#include "debug.h"
#include "cache.hpp"
#include "shared_cache.hpp"
#include "glz_decoded_image.h"
#include "glz_decoder.h"
#include "jpeg_decoder.h"
#include "zlib_decoder.h"
enum CanvasType {
CANVAS_TYPE_INVALID,
CANVAS_TYPE_SW,
CANVAS_TYPE_GL,
CANVAS_TYPE_GDI,
};
class PixmapCacheTreat {
public:
static inline pixman_image_t *get(pixman_image_t *surf)
{
return pixman_image_ref(surf);
}
static inline void release(pixman_image_t *surf)
{
pixman_image_unref(surf);
}
static const char* name() { return "pixmap";}
};
class SpiceImageCacheBase;
typedef SharedCache<pixman_image_t, PixmapCacheTreat, 1024, SpiceImageCacheBase> PixmapCache;
class SpiceImageCacheBase {
public:
SpiceImageCache base;
static void op_put(SpiceImageCache *c, uint64_t id, pixman_image_t *surface)
{
PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
cache->add(id, surface);
}
static void op_put_lossy(SpiceImageCache *c, uint64_t id, pixman_image_t *surface)
{
PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
cache->add(id, surface, TRUE);
}
static void op_replace_lossy(SpiceImageCache *c, uint64_t id, pixman_image_t *surface)
{
PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
cache->replace(id, surface);
}
static pixman_image_t* op_get(SpiceImageCache *c, uint64_t id)
{
PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
return cache->get(id);
}
static pixman_image_t* op_get_lossless(SpiceImageCache *c, uint64_t id)
{
PixmapCache* cache = reinterpret_cast<PixmapCache*>(c);
return cache->get_lossless(id);
}
SpiceImageCacheBase()
{
static SpiceImageCacheOps cache_ops = {
op_put,
op_get,
op_put_lossy,
op_replace_lossy,
op_get_lossless
};
base.ops = &cache_ops;
}
};
class CachedPalette {
public:
CachedPalette(SpicePalette* palette)
: _refs(1)
{
int size = sizeof(SpicePalette) + palette->num_ents * sizeof(uint32_t);
CachedPalette **ptr = (CachedPalette **)new uint8_t[size + sizeof(CachedPalette *)];
*ptr = this;
_palette = (SpicePalette*)(ptr + 1);
memcpy(_palette, palette, size);
}
CachedPalette* ref()
{
_refs++;
return this;
}
void unref()
{
if (--_refs == 0) {
delete this;
}
}
static void unref(SpicePalette *pal)
{
CachedPalette **ptr = (CachedPalette **)pal;
(*(ptr - 1))->unref();
}
SpicePalette* palette() { return _palette;}
private:
~CachedPalette()
{
delete[] (uint8_t *)((CachedPalette **)_palette - 1);
}
private:
int _refs;
SpicePalette* _palette;
};
class PaletteCacheTreat {
public:
static inline CachedPalette* get(CachedPalette* palette)
{
return palette->ref();
}
static inline void release(CachedPalette* palette)
{
palette->unref();
}
static const char* name() { return "palette";}
};
class SpicePaletteCacheBase;
typedef Cache<CachedPalette, PaletteCacheTreat, 1024, SpicePaletteCacheBase> PaletteCache;
class SpicePaletteCacheBase {
public:
SpicePaletteCache base;
static void op_put(SpicePaletteCache *c, SpicePalette *palette)
{
PaletteCache* cache = reinterpret_cast<PaletteCache*>(c);
AutoRef<CachedPalette> cached_palette(new CachedPalette(palette));
cache->add(palette->unique, *cached_palette);
}
static SpicePalette* op_get(SpicePaletteCache *c, uint64_t id)
{
PaletteCache* cache = reinterpret_cast<PaletteCache*>(c);
return cache->get(id)->palette();
}
static void op_release (SpicePaletteCache *c,
SpicePalette *palette)
{
CachedPalette::unref(palette);
}
SpicePaletteCacheBase()
{
static SpicePaletteCacheOps cache_ops = {
op_put,
op_get,
op_release
};
base.ops = &cache_ops;
}
};
/* Lz decoder related classes */
class GlzDecodedSurface: public GlzDecodedImage {
public:
GlzDecodedSurface(uint64_t id, uint64_t win_head_id, uint8_t *data, int size,
int bytes_per_pixel, pixman_image_t *surface)
: GlzDecodedImage(id, win_head_id, data, size, bytes_per_pixel)
, _surface (surface)
{
pixman_image_ref(_surface);
}
virtual ~GlzDecodedSurface()
{
pixman_image_unref(_surface);
}
private:
pixman_image_t *_surface;
};
class GlzDecodeSurfaceHandler: public GlzDecodeHandler {
public:
virtual GlzDecodedImage *alloc_image(void *opaque_usr_info, uint64_t image_id,
uint64_t image_win_head_id, LzImageType type,
int width, int height, int gross_pixels,
int n_bytes_per_pixel, bool top_down)
{
ASSERT(type == LZ_IMAGE_TYPE_RGB32 || type == LZ_IMAGE_TYPE_RGBA);
pixman_image_t *surface =
alloc_lz_image_surface((LzDecodeUsrData *)opaque_usr_info,
type == LZ_IMAGE_TYPE_RGBA ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
width, height, gross_pixels, top_down);
uint8_t *data = (uint8_t *)pixman_image_get_data(surface);
if (!top_down) {
data = data - (gross_pixels / height) * n_bytes_per_pixel * (height - 1);
}
return (new GlzDecodedSurface(image_id, image_win_head_id, data,
gross_pixels, n_bytes_per_pixel, surface));
}
};
/* TODO: unite with the window debug callbacks? */
class GlzDecoderCanvasDebug: public GlzDecoderDebug {
public:
virtual SPICE_GNUC_NORETURN void error(const std::string& str)
{
throw Exception(str);
}
virtual void warn(const std::string& str)
{
LOG_WARN("%s", str.c_str());
}
virtual void info(const std::string& str)
{
LOG_INFO("%s", str.c_str());
}
};
class Canvas;
typedef std::map<uint32_t, Canvas*> SurfacesCanvasesMap;
class SurfacesCache: public SpiceImageSurfaces, public SurfacesCanvasesMap {
public:
SurfacesCache();
bool exist(uint32_t surface_id);
};
class Canvas {
public:
Canvas(PixmapCache& bits_cache, PaletteCache& palette_cache,
GlzDecoderWindow &glz_decoder_window, SurfacesCache& csurfaces);
virtual ~Canvas();
virtual void copy_pixels(const QRegion& region, RedDrawable* dc,
const PixmapHeader* pixmap) = 0;
virtual void copy_pixels(const QRegion& region, RedDrawable& dc) = 0;
virtual void thread_touch() = 0;
void clear();
void draw_fill(SpiceMsgDisplayDrawFill& fill, int size);
void draw_text(SpiceMsgDisplayDrawText& text, int size);
void draw_opaque(SpiceMsgDisplayDrawOpaque& opaque, int size);
void draw_copy(SpiceMsgDisplayDrawCopy& copy, int size);
void draw_transparent(SpiceMsgDisplayDrawTransparent& transparent, int size);
void draw_alpha_blend(SpiceMsgDisplayDrawAlphaBlend& alpha_blend, int size);
void copy_bits(SpiceMsgDisplayCopyBits& copy_bits, int size);
void draw_blend(SpiceMsgDisplayDrawBlend& blend, int size);
void draw_blackness(SpiceMsgDisplayDrawBlackness& blackness, int size);
void draw_whiteness(SpiceMsgDisplayDrawWhiteness& whiteness, int size);
void draw_invers(SpiceMsgDisplayDrawInvers& invers, int size);
void draw_rop3(SpiceMsgDisplayDrawRop3& rop3, int size);
void draw_stroke(SpiceMsgDisplayDrawStroke& stroke, int size);
void draw_composite(SpiceMsgDisplayDrawComposite& composite, int size);
void put_image(
#ifdef WIN32
HDC dc,
#endif
const PixmapHeader& image,
const SpiceRect& dest, const QRegion* clip);
virtual CanvasType get_pixmap_type() { return CANVAS_TYPE_INVALID; }
virtual SpiceCanvas *get_internal_canvas() { return _canvas; }
protected:
virtual void touched_bbox(const SpiceRect *bbox) {};
PixmapCache& pixmap_cache() { return _pixmap_cache;}
PaletteCache& palette_cache() { return _palette_cache;}
SurfacesCache& surfaces_cache() { return _surfaces_cache;}
GlzDecoder& glz_decoder() {return _glz_decoder;}
JpegDecoder& jpeg_decoder() { return _jpeg_decoder;}
ZlibDecoder& zlib_decoder() { return _zlib_decoder;}
private:
void begin_draw(SpiceMsgDisplayBase& base, int size, size_t min_size);
protected:
SpiceCanvas* _canvas;
private:
PixmapCache& _pixmap_cache;
PaletteCache& _palette_cache;
GlzDecodeSurfaceHandler _glz_handler;
GlzDecoderCanvasDebug _glz_debug;
GlzDecoder _glz_decoder;
JpegDecoder _jpeg_decoder;
ZlibDecoder _zlib_decoder;
SurfacesCache& _surfaces_cache;
};
#endif

View File

@ -1,388 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
Author:
yhalperi@redhat.com
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "client_net_socket.h"
#include "debug.h"
#include <spice/error_codes.h>
#include "utils.h"
ClientNetSocket::ClientNetSocket(uint16_t id, const struct in_addr& dst_addr, uint16_t dst_port,
ProcessLoop& process_loop, EventHandler& event_handler)
: _id (id)
, _local_addr (dst_addr)
, _local_port (dst_port)
, _peer (INVALID_SOCKET)
, _process_loop (process_loop)
, _event_handler (event_handler)
, _num_recv_tokens (0)
, _send_message (NULL)
, _send_pos (0)
, _status (SOCKET_STATUS_CLOSED)
, _fin_pending (false)
, _close_pending (false)
{
}
ClientNetSocket::~ClientNetSocket()
{
close();
}
bool ClientNetSocket::connect(uint32_t recv_tokens)
{
struct sockaddr_in addr;
int no_delay;
ASSERT(_peer == INVALID_SOCKET && _status == SOCKET_STATUS_CLOSED);
addr.sin_port = _local_port;
addr.sin_addr.s_addr = _local_addr.s_addr;
addr.sin_family = AF_INET;
if ((_peer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
int err = sock_error();
THROW("%s: failed to create socket: %s", __FUNCTION__, sock_err_message(err));
}
no_delay = 1;
if (setsockopt(_peer, IPPROTO_TCP, TCP_NODELAY,
(const char*)&no_delay, sizeof(no_delay)) == SOCKET_ERROR) {
LOG_WARN("set TCP_NODELAY failed");
}
LOG_INFO("connect to ip=%s port=%d (connection_id=%d)",
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), _id);
if (::connect(_peer, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == SOCKET_ERROR) {
int err = sock_error();
closesocket(_peer);
_peer = INVALID_SOCKET;
LOG_INFO("connect to ip=%s port=%d failed %s (connection_id=%d)",
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), sock_err_message(err), _id);
return false;
}
_process_loop.add_socket(*this);
_status = SOCKET_STATUS_OPEN;
_num_recv_tokens = recv_tokens;
return true;
}
void ClientNetSocket::push_disconnect()
{
if ((_status == SOCKET_STATUS_CLOSED) || _close_pending) {
THROW("%s: disconnect attempt for disconnected socket %s %d", __FUNCTION__,
inet_ntoa(_local_addr), ntohs(_local_port));
}
_close_pending = true;
if (!during_send()) {
close_and_tell();
}
}
void ClientNetSocket::push_fin()
{
if ((_status == SOCKET_STATUS_OPEN) || (_status == SOCKET_STATUS_RECEIVED_FIN)) {
_fin_pending = true;
if (!during_send()) {
try {
apply_guest_fin();
} catch (ClientNetSocket::ShutdownExcpetion&) {
close_and_tell();
}
}
} else {
THROW("%s: unexpected fin connection_id=%d (status=%d)", __FUNCTION__,
_id, _status);
}
}
void ClientNetSocket::add_recv_tokens(uint32_t num_tokens)
{
if ((_status == SOCKET_STATUS_CLOSED) || _close_pending) {
THROW("%s: ack attempt for disconnected socket connection_id=%d", __FUNCTION__,
_id);
}
_num_recv_tokens += num_tokens;
// recv might have not been called because tokens weren't available
if (_num_recv_tokens && (_num_recv_tokens == num_tokens)) {
if (can_receive()) {
receive();
}
}
}
void ClientNetSocket::push_send(SendBuffer& buf)
{
if (!can_send()) {
THROW("%s: unexpected send attempt for connection_id=%d (status = %d)",
__FUNCTION__, _id, _status);
}
if (_fin_pending || _close_pending) {
THROW("%s: unexpected send attempt for connection_id=%d - shutdown send pending",
__FUNCTION__, _id);
}
_send_messages.push_back(buf.ref());
send();
}
void ClientNetSocket::on_event()
{
if (can_send()) {
send();
}
if (!during_send()) {
if (_close_pending) {
close_and_tell();
} else if (_fin_pending) {
apply_guest_fin();
}
}
if (can_receive()) {
receive();
}
}
void ClientNetSocket::apply_guest_fin()
{
if (_status == SOCKET_STATUS_OPEN) {
if (shutdown(_peer, SHUT_WR) == SOCKET_ERROR) {
int err = sock_error();
LOG_INFO("shutdown in connection_id=%d failed %s", _id, sock_err_message(err));
throw ClientNetSocket::ShutdownExcpetion();
}
_fin_pending = false;
_status = SOCKET_STATUS_SENT_FIN;
} else if (_status == SOCKET_STATUS_RECEIVED_FIN) {
close_and_tell();
}
}
void ClientNetSocket::handle_client_fin()
{
if (_status == SOCKET_STATUS_OPEN) {
_status = SOCKET_STATUS_RECEIVED_FIN;
_event_handler.on_socket_fin_recv(*this);
} else if (_status == SOCKET_STATUS_SENT_FIN) {
close_and_tell();
}
}
inline bool ClientNetSocket::during_send()
{
return ((!_send_messages.empty()) || _send_message);
}
inline bool ClientNetSocket::can_send()
{
return ((_status == SOCKET_STATUS_OPEN) || (_status == SOCKET_STATUS_RECEIVED_FIN));
}
inline bool ClientNetSocket::can_receive()
{
return ((_status == SOCKET_STATUS_OPEN) || (_status == SOCKET_STATUS_SENT_FIN));
}
void ClientNetSocket::send_message_done()
{
_send_message->unref();
_send_message = NULL;
_send_pos = 0;
_event_handler.on_socket_message_send_done(*this);
}
void ClientNetSocket::send()
{
ASSERT(_peer != INVALID_SOCKET);
try {
if (_send_message) {
_send_pos += send_buf(_send_message->data() + _send_pos,
_send_message->size() - _send_pos);
if (_send_pos != _send_message->size()) {
return;
} else {
send_message_done();
}
}
while (!_send_messages.empty()) {
_send_message = _send_messages.front();
_send_messages.pop_front();
_send_pos = send_buf(_send_message->data(), _send_message->size());
if (_send_pos != _send_message->size()) {
return;
} else {
send_message_done();
}
}
} catch (ClientNetSocket::SendException&) {
close_and_tell();
}
}
uint32_t ClientNetSocket::send_buf(const uint8_t* buf, uint32_t size)
{
const uint8_t* pos = buf;
ASSERT(_peer != INVALID_SOCKET);
while (size) {
int now;
if ((now = ::send(_peer, (char*)pos, size, MSG_NOSIGNAL)) == SOCKET_ERROR) {
int err = sock_error();
if (err == WOULDBLOCK_ERR) {
break;
}
if (err == INTERRUPTED_ERR) {
continue;
}
LOG_INFO("send in connection_id=%d failed %s", _id, sock_err_message(err));
throw ClientNetSocket::SendException();
}
size -= now;
pos += now;
}
return pos - buf;
}
void ClientNetSocket::receive()
{
ASSERT(_peer != INVALID_SOCKET);
bool shutdown;
while (_num_recv_tokens) {
ReceiveBuffer& rcv_buf = alloc_receive_buffer();
uint32_t size;
try {
size = receive_buf(rcv_buf.buf(), rcv_buf.buf_max_size(), shutdown);
} catch (ClientNetSocket::ReceiveException&) {
rcv_buf.release_buf();
close_and_tell();
return;
}
if (size) {
rcv_buf.set_buf_size(size);
_num_recv_tokens--;
_event_handler.on_socket_message_recv_done(*this, rcv_buf);
} else {
rcv_buf.release_buf();
}
if (shutdown) {
handle_client_fin();
return;
}
if (size < rcv_buf.buf_max_size()) {
return;
}
}
}
uint32_t ClientNetSocket::receive_buf(uint8_t* buf, uint32_t max_size, bool& shutdown)
{
uint8_t* pos = buf;
ASSERT(_peer != INVALID_SOCKET);
shutdown = false;
while (max_size) {
int now;
if ((now = ::recv(_peer, (char*)pos, max_size, 0)) <= 0) {
if (now == 0) {
shutdown = true;
break; // a case where fin is received, but before that, there is a msg
}
int err = sock_error();
if (err == WOULDBLOCK_ERR) {
break;
}
if (err == INTERRUPTED_ERR) {
continue;
}
LOG_INFO("receive in connection_id=%d failed errno=%s", _id, sock_err_message(err));
throw ClientNetSocket::ReceiveException();
}
max_size -= now;
pos += now;
}
return (pos - buf);
}
void ClientNetSocket::release_wait_send_messages()
{
if (_send_message) {
_send_message->unref();
_send_message = NULL;
_send_pos = 0;
}
while (!_send_messages.empty()) {
_send_messages.front()->unref();
_send_messages.pop_front();
}
}
void ClientNetSocket::close()
{
release_wait_send_messages();
apply_disconnect();
}
void ClientNetSocket::close_and_tell()
{
close();
_event_handler.on_socket_disconnect(*this);
}
void ClientNetSocket::apply_disconnect()
{
if (_peer != INVALID_SOCKET) {
_process_loop.remove_socket(*this);
closesocket(_peer);
_peer = INVALID_SOCKET;
LOG_INFO("closing connection_id=%d", _id);
}
_status = SOCKET_STATUS_CLOSED;
_close_pending = false;
_fin_pending = false;
}

View File

@ -1,154 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
Author:
yhalperi@redhat.com
*/
#ifndef _H_CLIENT_NET_SOCKET
#define _H_CLIENT_NET_SOCKET
#include "platform_utils.h"
#include "common.h"
#include "process_loop.h"
/* interface for connections inside client LAN */
typedef enum {
SOCKET_STATUS_OPEN,
SOCKET_STATUS_SENT_FIN,
SOCKET_STATUS_RECEIVED_FIN,
SOCKET_STATUS_CLOSED,
} SocketStatus;
class ClientNetSocket: public EventSources::Socket {
public:
class ReceiveBuffer;
class SendBuffer;
class EventHandler;
class SendException {};
class ReceiveException {};
class ShutdownExcpetion {};
ClientNetSocket(uint16_t id, const struct in_addr& dst_addr, uint16_t dst_port,
ProcessLoop& process_loop, ClientNetSocket::EventHandler& event_handler);
virtual ~ClientNetSocket();
bool connect(uint32_t recv_tokens);
void push_disconnect();
void push_fin();
void push_send(SendBuffer& buf);
void add_recv_tokens(uint32_t num_tokens);
bool is_connected() {return _status != SOCKET_STATUS_CLOSED;}
inline uint16_t id() {return _id;}
inline const struct in_addr& local_addr() {return _local_addr;}
inline uint16_t local_port() {return _local_port;}
/* EventSources::Socket interface */
void on_event();
int get_socket() {return _peer;}
protected:
virtual ReceiveBuffer& alloc_receive_buffer() = 0;
private:
void send();
void receive();
uint32_t send_buf(const uint8_t* buf, uint32_t size);
uint32_t receive_buf(uint8_t* buf, uint32_t max_size, bool& shutdown);
bool can_receive();
bool can_send();
void apply_disconnect();
void apply_guest_fin();
void close();
void close_and_tell();
void handle_client_fin();
bool during_send();
void release_wait_send_messages();
void clear();
void send_message_done();
private:
uint16_t _id;
struct in_addr _local_addr;
uint16_t _local_port;
SOCKET _peer;
ProcessLoop& _process_loop;
EventHandler& _event_handler;
uint32_t _num_recv_tokens;
std::list<SendBuffer*> _send_messages;
SendBuffer* _send_message;
uint32_t _send_pos;
SocketStatus _status;
bool _fin_pending;
bool _close_pending;
};
class ClientNetSocket::ReceiveBuffer {
public:
ReceiveBuffer() {}
virtual uint8_t* buf() = 0;
virtual uint32_t buf_max_size() = 0;
virtual void set_buf_size(uint32_t size) = 0;
virtual void release_buf() = 0;
protected:
virtual ~ReceiveBuffer() {}
};
class ClientNetSocket::SendBuffer {
public:
SendBuffer() {};
virtual const uint8_t* data() = 0;
virtual uint32_t size() = 0;
virtual ClientNetSocket::SendBuffer* ref() = 0;
virtual void unref() = 0;
protected:
virtual ~SendBuffer() {}
};
class ClientNetSocket::EventHandler {
public:
EventHandler() {}
virtual ~EventHandler() {}
virtual void on_socket_message_recv_done(ClientNetSocket& sckt, ReceiveBuffer& buf) = 0;
virtual void on_socket_message_send_done(ClientNetSocket& sckt) = 0;
virtual void on_socket_disconnect(ClientNetSocket& sckt) = 0;
virtual void on_socket_fin_recv(ClientNetSocket& sckt) = 0;
};
#endif

View File

@ -1,518 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include <getopt.h>
#include <iostream>
#include "cmd_line_parser.h"
#include "utils.h"
#include "debug.h"
#define DISABLE_ABBREVIATE
CmdLineParser::Option::Option(int in_id, const std::string& in_name, char in_short_name,
OptionType in_type, const std::string& in_help,
const std::string& in_arg_name)
: id (in_id)
, name (in_name)
, arg_name (in_arg_name)
, type (in_type)
, short_name (in_short_name)
, help (in_help)
, optional (true)
, is_set (false)
, separator (0)
{
}
CmdLineParser::CmdLineParser(std::string description, bool allow_positional_args)
: _description (description)
, _short_options ("+")
, _argc (0)
, _argv (NULL)
, _multi_args (NULL)
, _multi_next (NULL)
, _multi_separator (0)
, _positional_args (allow_positional_args)
, _done (false)
{
//Enables multiple instantiations. One at a time, not thread-safe.
optind = 1;
opterr = 1;
optopt = 0;
optarg = 0;
}
CmdLineParser::~CmdLineParser()
{
Options::iterator iter = _options.begin();
for (; iter != _options.end(); ++iter) {
delete *iter;
}
delete[] _multi_args;
}
void CmdLineParser::add_private(int id, const std::string& name, char short_name,
OptionType type, const std::string& help,
const std::string& arg_name)
{
if (_argv) {
THROW("unexpected");
}
if (find(id)) {
THROW("exist");
}
if (name.size() == 0) {
THROW("invalid name");
}
if (find(name)) {
THROW("name exist");
}
if (short_name != 0) {
if (!isalnum(short_name) || short_name == 'W') {
THROW("invalid short name");
}
if (find(short_name)) {
THROW("short name exist");
}
}
if (help.size() == 0) {
THROW("invalid help string");
}
if (help.find_first_of('\t') != std::string::npos) {
THROW("tab is not allow in help string");
}
_options.push_back(new Option(id, name, short_name, type, help, arg_name));
}
void CmdLineParser::add(int id, const std::string& name, const std::string& help, char short_name)
{
if (id < OPTION_FIRST_AVAILABLE) {
THROW("invalid id");
}
add_private(id, name, short_name, NO_ARGUMENT, help, "");
}
void CmdLineParser::add(int id, const std::string& name, const std::string& help,
const std::string& arg_name, bool required_arg, char short_name)
{
if (id < OPTION_FIRST_AVAILABLE) {
THROW("invalid id");
}
if (arg_name.size() == 0) {
THROW("invalid arg name");
}
add_private(id, name, short_name, required_arg ? REQUIRED_ARGUMENT : OPTIONAL_ARGUMENT, help,
arg_name);
}
void CmdLineParser::set_multi(int id, char separator)
{
if (_argv) {
THROW("unexpected");
}
if (!ispunct(separator)) {
THROW("invalid separator");
}
Option* opt = find(id);
if (!opt) {
THROW("not found");
}
if (opt->type == NO_ARGUMENT) {
THROW("can't set multi for option without argument");
}
opt->separator = separator;
}
void CmdLineParser::set_required(int id)
{
if (_argv) {
THROW("unexpected");
}
Option* opt = find(id);
if (!opt) {
THROW("not found");
}
opt->optional = false;
}
CmdLineParser::Option* CmdLineParser::find(int id)
{
Options::iterator iter = _options.begin();
for (; iter != _options.end(); ++iter) {
if ((*iter)->id == id) {
return *iter;
}
}
return NULL;
}
bool CmdLineParser::is_set(int id)
{
Option *opt = find(id);
if (!opt) {
THROW("not found");
}
return opt->is_set;
}
CmdLineParser::Option* CmdLineParser::find(const std::string& name)
{
Options::iterator iter = _options.begin();
for (; iter != _options.end(); ++iter) {
if ((*iter)->name == name) {
return *iter;
}
}
return NULL;
}
CmdLineParser::Option* CmdLineParser::find(char short_name)
{
if (short_name == 0) {
return NULL;
}
Options::iterator iter = _options.begin();
for (; iter != _options.end(); ++iter) {
if ((*iter)->short_name == short_name) {
return *iter;
}
}
return NULL;
}
CmdLineParser::Option* CmdLineParser::find_missing_opt()
{
Options::iterator iter = _options.begin();
for (; iter != _options.end(); ++iter) {
CmdLineParser::Option* opt = *iter;
if (!opt->optional && !opt->is_set) {
return opt;
}
}
return NULL;
}
void CmdLineParser::build()
{
Options::iterator iter = _options.begin();
_long_options.resize(_options.size() + 1);
for (int i = 0; iter != _options.end(); ++iter, i++) {
CmdLineParser::Option* opt = *iter;
struct option& long_option = _long_options[i];
long_option.name = opt->name.c_str();
switch (opt->type) {
case NO_ARGUMENT:
long_option.has_arg = no_argument;
break;
case OPTIONAL_ARGUMENT:
long_option.has_arg = optional_argument;
break;
case REQUIRED_ARGUMENT:
long_option.has_arg = required_argument;
break;
}
long_option.flag = &long_option.val;
long_option.val = opt->id;
if (opt->short_name != 0) {
_short_options += opt->short_name;
switch (opt->type) {
case OPTIONAL_ARGUMENT:
_short_options += "::";
break;
case REQUIRED_ARGUMENT:
_short_options += ":";
break;
case NO_ARGUMENT:
break;
}
}
}
struct option& long_option = _long_options[_long_options.size() - 1];
long_option.flag = 0;
long_option.has_arg = 0;
long_option.name = NULL;
long_option.val = 0;
}
void CmdLineParser::begin(int argc, char** argv)
{
if (_argv) {
THROW("unexpected");
}
if (!argv || argc < 1) {
THROW("invalid args");
}
add_private(CmdLineParser::OPTION_HELP, "help", 0, NO_ARGUMENT, "show command help", "");
opterr = 0;
_argv = argv;
_argc = argc;
build();
}
char* CmdLineParser::start_multi(char *optarg, char separator)
{
if (!optarg) {
return NULL;
}
_multi_args = new char[strlen(optarg) + 1];
_multi_separator = separator;
strcpy(_multi_args, optarg);
if ((_multi_next = strchr(_multi_args, _multi_separator))) {
*(_multi_next++) = 0;
}
return _multi_args;
}
char* CmdLineParser::next_multi()
{
if (!_multi_next) {
_multi_separator = 0;
delete[] _multi_args;
_multi_args = NULL;
return NULL;
}
char* ret = _multi_next;
if ((_multi_next = strchr(_multi_next, _multi_separator))) {
*(_multi_next++) = 0;
}
return ret;
}
int CmdLineParser::get_option(char** val)
{
CmdLineParser::Option* opt_obj;
if (!_argv) {
THROW("unexpected");
}
if (_multi_args) {
THROW("in multi args mode");
}
if (_done) {
THROW("is done");
}
int long_index;
int opt = getopt_long(_argc, _argv, _short_options.c_str(), &_long_options[0], &long_index);
switch (opt) {
case 0: {
if (!(opt_obj = find(_long_options[long_index].val))) {
THROW("long option no found");
}
#ifdef DISABLE_ABBREVIATE
int name_pos =
(opt_obj->type == REQUIRED_ARGUMENT && optarg[-1] != '=')
? optind - 2
: optind - 1;
std::string cmd_name(_argv[name_pos] + 2);
if (cmd_name.find(opt_obj->name) != 0) {
Platform::term_printf("%s: invalid abbreviated option '--%s'\n", _argv[0], cmd_name.c_str());
return OPTION_ERROR;
}
#endif
if (opt_obj->separator) {
*val = start_multi(optarg, opt_obj->separator);
} else {
*val = optarg;
}
opt_obj->is_set = true;
return opt_obj->id;
}
case -1: {
*val = NULL;
if (!_positional_args && optind != _argc) {
Platform::term_printf("%s: unexpected positional arguments\n", _argv[0]);
return OPTION_ERROR;
}
if ((opt_obj = find_missing_opt())) {
Platform::term_printf("%s: option --%s is required\n", _argv[0], opt_obj->name.c_str());
return OPTION_ERROR;
}
_done = true;
return OPTION_DONE;
}
case '?':
if (optopt >= 255) {
opt_obj = find(optopt);
ASSERT(opt_obj);
#ifdef DISABLE_ABBREVIATE
std::string cmd_name(_argv[optind - 1] + 2);
if (cmd_name.find(opt_obj->name) != 0) {
Platform::term_printf("%s: invalid option '--%s'\n", _argv[0], cmd_name.c_str());
return OPTION_ERROR;
}
#endif
Platform::term_printf("%s: option --%s requires an argument\n",
_argv[0], opt_obj->name.c_str());
} else if (optopt == 0) {
Platform::term_printf("%s: invalid option '%s'\n", _argv[0], _argv[optind - 1]);
} else if ((opt_obj = find((char)optopt))) {
Platform::term_printf("%s: option '-%c' requires an argument\n",
_argv[0], opt_obj->short_name);
} else {
Platform::term_printf("%s: invalid option '-%c'\n", _argv[0], char(optopt));
}
return OPTION_ERROR;
default:
if (opt > 255 || !(opt_obj = find((char)opt))) {
*val = NULL;
return OPTION_ERROR;
}
if (opt_obj->separator) {
*val = start_multi(optarg, opt_obj->separator);
} else {
*val = optarg;
}
opt_obj->is_set = true;
return opt_obj->id;
}
}
char* CmdLineParser::next_argument()
{
if (!_argv) {
THROW("unexpected");
}
if (_multi_args) {
return next_multi();
}
if (!_done) {
THROW("not done");
}
if (optind == _argc) {
return NULL;
}
return _argv[optind++];
}
void CmdLineParser::show_help()
{
static const int HELP_START_POS = 30;
static const unsigned HELP_WIDTH = 80 - HELP_START_POS;
std::ostringstream os;
os << _argv[0] << " - " << _description.c_str() << "\n\noptions:\n\n";
Options::iterator iter = _options.begin();
for (; iter != _options.end(); ++iter) {
CmdLineParser::Option* opt = *iter;
if (opt->short_name) {
os << " -" << opt->short_name << ", ";
} else {
os << " ";
}
os << "--" << opt->name;
if (opt->type == OPTIONAL_ARGUMENT) {
os << "[=";
} else if (opt->type == REQUIRED_ARGUMENT) {
os << " <";
}
if (opt->type == OPTIONAL_ARGUMENT || opt->type == REQUIRED_ARGUMENT) {
if (opt->separator) {
os << opt->arg_name << opt->separator << opt->arg_name << "...";
} else {
os << opt->arg_name;
}
}
if (opt->type == OPTIONAL_ARGUMENT) {
os << "]";
} else if (opt->type == REQUIRED_ARGUMENT) {
os << ">";
}
int skip = HELP_START_POS - os.str().size();
if (skip < 2) {
os << "\n ";
} else {
while (skip--) {
os << " ";
}
}
int line_count = 0;
std::istringstream is(opt->help);
std::string line;
std::getline(is, line);
do {
if (line_count++) {
os << " ";
}
if (line.size() > HELP_WIDTH) {
size_t last_space, now = HELP_WIDTH;
std::string sub;
sub.append(line, 0, now);
if ((last_space = sub.find_last_of(' ')) != std::string::npos) {
now = last_space;
sub.resize(now++);
}
os << sub << "\n";
line = line.substr(now, line.size() - now);
} else {
os << line << "\n";
line.clear();
}
} while (line.size() || std::getline(is, line));
}
os << "\n";
Platform::term_printf("%s", os.str().c_str());
}

View File

@ -1,104 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CMD_LINE_PARSER
#define _H_CMD_LINE_PARSER
class CmdLineParser {
public:
enum {
OPTION_ERROR = -1,
OPTION_DONE = 0,
OPTION_HELP = 256,
OPTION_FIRST_AVAILABLE,
};
CmdLineParser(std::string description, bool allow_positional_args);
virtual ~CmdLineParser();
void add(int id, const std::string& name, const std::string& help,
char short_name = 0);
void add(int id, const std::string& name, const std::string& help,
const std::string& arg_name, bool required_arg, char short_name = 0);
void set_multi(int id, char separator);
void set_required(int id);
void begin(int argc, char** argv);
int get_option(char** val);
char* next_argument();
bool is_set(int id);
void show_help();
private:
class Option;
enum OptionType {
NO_ARGUMENT,
OPTIONAL_ARGUMENT,
REQUIRED_ARGUMENT,
};
void add_private(int id, const std::string& name, char short_name, OptionType type,
const std::string& help, const std::string& arg_name);
Option* find(char short_name);
Option* find(int id);
Option* find(const std::string& name);
Option* find_missing_opt();
void build();
char* start_multi(char *optarg, char separator);
char* next_multi();
private:
class Option {
public:
Option(int in_id, const std::string& in_name, char in_short_name, OptionType in_type,
const std::string& in_help, const std::string& arg_name);
public:
int id;
std::string name;
std::string arg_name;
OptionType type;
char short_name;
std::string help;
bool optional;
bool is_set;
char separator;
};
std::string _description;
std::vector<struct option> _long_options;
std::string _short_options;
typedef std::list<Option*> Options;
Options _options;
int _argc;
char** _argv;
char* _multi_args;
char* _multi_next;
char _multi_separator;
bool _positional_args;
bool _done;
};
#endif

View File

@ -1,92 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_COMMON
#define _H_COMMON
#ifndef WIN32
#include "config.h"
#endif
#ifndef _WIN32_WCE
#include <errno.h>
#endif
#ifndef _WIN32
#include <inttypes.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <exception>
#include <list>
#include <string.h>
#ifdef WIN32
#ifdef __GNUC__
#define UNICODE 1
#define _UNICODE 1
#if !defined __MINGW32__
#define WINVER 0x0501
#define swprintf_s(_str, _len, _fmt, ...) \
swprintf(_str, _fmt, ## __VA_ARGS__)
#define vsnprintf_s(_str, _len1, _len2, _fmt, _valist) \
vsnprintf(_str, _len2, _fmt, _valist)
#define _ftime_s(_t) _ftime(_t)
#endif
#endif
#include <winsock2.h>
#include <windows.h>
#ifndef __GNUC__
#pragma warning(disable:4355)
#pragma warning(disable:4996)
#pragma warning(disable:4200)
extern const char* PACKAGE_VERSION;
#endif
#define strcasecmp stricmp
#else
#include <unistd.h>
#include <X11/X.h>
#ifdef USE_OPENGL
#include <GL/glx.h>
#endif
#endif
#ifdef __GNUC__
#if __SIZEOF_POINTER__ == 8
#define RED64
#endif
#elif defined(_WIN64)
#define RED64
#endif
#if defined(_WIN32) && !defined(PRIu64)
#define PRIu64 "I64u"
#endif
#include <spice/types.h>
#include "red_types.h"
#endif

View File

@ -1,448 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "controller.h"
#include <spice/controller_prot.h>
#include "cmd_line_parser.h"
#include "menu.h"
#include "utils.h"
#include "debug.h"
#include "platform.h"
#ifdef WIN32
#define PIPE_NAME_MAX_LEN 50
#define PIPE_NAME "SpiceController-%lu"
#endif
Controller::Controller(ControllerInterface *handler)
: _handler (handler)
, _exclusive (false)
, _refs (1)
{
ASSERT(_handler);
#ifdef WIN32
char pipe_name[PIPE_NAME_MAX_LEN];
snprintf(pipe_name, PIPE_NAME_MAX_LEN, PIPE_NAME, Platform::get_process_id());
#else
const char *pipe_name = getenv("SPICE_XPI_SOCKET");
if (!pipe_name) {
LOG_ERROR("Failed to get a controller connection (SPICE_XPI_SOCKET)");
throw Exception("Failed to get a controller connection (SPICE_XPI_SOCKET)");
}
#endif
LOG_INFO("Creating a controller connection %s", pipe_name);
_pipe = NamedPipe::create(pipe_name, *this);
if (!_pipe) {
LOG_ERROR("Failed to create a controller connection");
}
}
Controller::~Controller()
{
std::map<NamedPipe::ConnectionRef, ControllerConnection*>::const_iterator conn;
for (conn = _connections.begin(); conn != _connections.end(); ++conn) {
conn->second->reset_handler();
delete conn->second;
}
if (_pipe) {
NamedPipe::destroy(_pipe);
}
}
NamedPipe::ConnectionInterface& Controller::create()
{
ControllerConnection *conn = new ControllerConnection(_handler, *this);
if (conn == NULL) {
throw Exception("Error allocating a new controller connection");
}
return *conn;
}
bool Controller::set_exclusive(bool exclusive)
{
if (_exclusive) {
LOG_ERROR("Cannot init controller, an exclusive controller already connected");
return false;
}
if (exclusive && _connections.size() > 1) {
LOG_ERROR("Cannot init exclusive controller, other controllers already connected");
return false;
}
_exclusive = exclusive;
return true;
}
void Controller::add_connection(NamedPipe::ConnectionRef conn_ref, ControllerConnection *conn)
{
_connections[conn_ref] = conn;
conn->on_data();
}
void Controller::remove_connection(NamedPipe::ConnectionRef conn_ref)
{
ControllerConnection *conn = _connections[conn_ref];
_connections.erase(conn_ref);
_exclusive = false;
delete conn;
}
void Controller::on_command(NamedPipe::ConnectionRef conn_ref, int32_t id)
{
ControllerConnection *conn = _connections[conn_ref];
ControllerValue msg;
ASSERT(conn);
msg.base.id = CONTROLLER_MENU_ITEM_CLICK;
msg.base.size = sizeof(msg);
msg.value = id;
conn->write_msg(&msg.base, msg.base.size);
}
ControllerConnection::ControllerConnection(ControllerInterface *handler, Controller& parent)
: _handler (handler)
, _parent (parent)
, _initialized (false)
, _write_pending (0)
, _write_pos (_write_buf)
, _read_pos (_read_buf)
, _port (-1)
, _sport (-1)
, _full_screen (false)
, _auto_display_res (false)
{
}
ControllerConnection::~ControllerConnection()
{
if (_opaque != NamedPipe::INVALID_CONNECTION) {
NamedPipe::destroy_connection(_opaque);
}
if (_handler) {
_handler->clear_menu_items(_opaque);
_handler->delete_menu();
}
}
void ControllerConnection::bind(NamedPipe::ConnectionRef conn_ref)
{
_opaque = conn_ref;
_parent.add_connection(conn_ref, this);
}
void ControllerConnection::on_data()
{
if (_write_pending) {
LOG_INFO("Resume pending write %d", _write_pending);
if (!write_msg(_write_pos, _write_pending)) {
return;
}
}
while (read_msgs());
}
bool ControllerConnection::read_msgs()
{
uint8_t *pos = _read_buf;
size_t nread = _read_pos - _read_buf;
int32_t size;
ASSERT(_handler);
ASSERT(_opaque != NamedPipe::INVALID_CONNECTION);
size = NamedPipe::read(_opaque, (uint8_t*)_read_pos, sizeof(_read_buf) - nread);
if (size == 0) {
return false;
} else if (size < 0) {
LOG_ERROR("Error reading from named pipe %d", size);
_parent.remove_connection(_opaque);
return false;
}
nread += size;
while (nread > 0) {
if (!_initialized && nread >= sizeof(ControllerInitHeader)) {
ControllerInitHeader *init = (ControllerInitHeader *)pos;
if (init->magic != CONTROLLER_MAGIC || init->version != CONTROLLER_VERSION) {
LOG_ERROR("Bad controller init, magic=0x%x version=%u", init->magic,
init->version);
_parent.remove_connection(_opaque);
return false;
}
if (nread < init->size) {
break;
}
if (!handle_init((ControllerInit*)init)) {
_parent.remove_connection(_opaque);
return false;
}
nread -= init->size;
pos += init->size;
_initialized = true;
}
if (!_initialized || nread < sizeof(ControllerMsg)) {
break;
}
ControllerMsg *hdr = (ControllerMsg *)pos;
if (hdr->size < sizeof(ControllerMsg)) {
LOG_ERROR("Bad controller message, size=%u", hdr->size);
_parent.remove_connection(_opaque);
return false;
}
if (nread < hdr->size) {
break;
}
handle_message(hdr);
nread -= hdr->size;
pos += hdr->size;
}
if (nread > 0 && pos != _read_buf) {
memmove(_read_buf, pos, nread);
}
_read_pos = _read_buf + nread;
return true;
}
bool ControllerConnection::write_msg(const void *buf, int len)
{
RecurciveLock lock(_write_lock);
uint8_t *pos;
int32_t written = 0;
ASSERT(_opaque != NamedPipe::INVALID_CONNECTION);
if (_write_pending && buf != _write_pos) {
if ((_write_pos + _write_pending + len > _write_buf + sizeof(_write_buf)) &&
!write_msg(_write_pos, _write_pending)) {
return false;
}
if (_write_pending) {
if (_write_pos + _write_pending + len > _write_buf + sizeof(_write_buf)) {
DBG(0, "Dropping message, due to insufficient space in write buffer");
return true;
}
memcpy(_write_pos + _write_pending, buf, len);
_write_pending += len;
}
}
pos = (uint8_t*)buf;
while (len && (written = NamedPipe::write(_opaque, pos, len)) > 0) {
pos += written;
len -= written;
}
if (len && written == 0) {
if (_write_pending) {
_write_pos = pos;
} else {
_write_pos = _write_buf;
memcpy(_write_buf, pos, len);
}
_write_pending = len;
} else if (written < 0) {
LOG_ERROR("Error writing to named pipe %d", written);
_parent.remove_connection(_opaque);
return false;
} else {
_write_pending = 0;
}
return true;
}
bool ControllerConnection::handle_init(ControllerInit *init)
{
ASSERT(_handler);
if (init->credentials != 0) {
LOG_ERROR("Controller menu has wrong credentials 0x%x", init->credentials);
return false;
}
if (!_parent.set_exclusive(init->flags & CONTROLLER_FLAG_EXCLUSIVE)) {
return false;
}
return true;
}
bool ControllerConnection::handle_message(ControllerMsg *hdr)
{
uint32_t value = ((ControllerValue*)hdr)->value;
char *data = (char*)((ControllerData*)hdr)->data;
ASSERT(_handler);
switch (hdr->id) {
case CONTROLLER_HOST:
_host.assign(data);
break;
case CONTROLLER_PORT:
_port = value;
break;
case CONTROLLER_SPORT:
_sport = value;
break;
case CONTROLLER_PASSWORD:
_password.assign(data);
break;
case CONTROLLER_SECURE_CHANNELS:
case CONTROLLER_DISABLE_CHANNELS:
return set_multi_val(hdr->id, data);
case CONTROLLER_TLS_CIPHERS:
return _handler->set_connection_ciphers(data, "Controller");
case CONTROLLER_CA_FILE:
return _handler->set_ca_file(data, "Controller");
case CONTROLLER_HOST_SUBJECT:
return _handler->set_host_cert_subject(data, "Controller");
case CONTROLLER_FULL_SCREEN:
_full_screen = !!(value & CONTROLLER_SET_FULL_SCREEN);
_handler->set_auto_display_res(!!(value & CONTROLLER_AUTO_DISPLAY_RES));
break;
case CONTROLLER_SET_TITLE: {
std::string str;
string_printf(str, "%s", data);
_handler->set_title(str);
break;
}
case CONTROLLER_HOTKEYS:
_handler->set_hotkeys(data);
break;
case CONTROLLER_CONNECT:
_handler->connect(_host, _port, _sport, _password);
break;
case CONTROLLER_SHOW:
_handler->show_me(_full_screen);
break;
case CONTROLLER_HIDE:
_handler->hide_me();
break;
case CONTROLLER_CREATE_MENU:
return create_menu((char*)data);
case CONTROLLER_DELETE_MENU:
_handler->delete_menu();
break;
#if USE_SMARTCARD
case CONTROLLER_ENABLE_SMARTCARD:
_handler->enable_smartcard(value);
break;
#endif
case CONTROLLER_SEND_CAD:
default:
LOG_ERROR("Ignoring an unknown/SEND_CAD controller message %u", hdr->id);
return false;
}
return true;
}
#ifdef WIN32
#define next_tok(str, delim, state) strtok(str, delim)
#else
#define next_tok(str, delim, state) strtok_r(str, delim, state)
#endif
bool ControllerConnection::create_menu(char* resource)
{
bool ret = true;
#ifndef WIN32
char* item_state = 0;
#endif
char* next_item;
const char* param;
const char* text;
int parent_id;
int flags;
int state;
int id;
ASSERT(_handler);
AutoRef<Menu> app_menu(_handler->get_app_menu());
AutoRef<Menu> menu(new Menu((*app_menu)->get_target(), ""));
char* item = next_tok(resource, CONTROLLER_MENU_ITEM_DELIMITER, &item_state);
while (item != NULL) {
next_item = item + strlen(item) + 1;
ret = ret && (param = next_tok(item, CONTROLLER_MENU_PARAM_DELIMITER, &item_state)) &&
sscanf(param, "%d", &parent_id);
ret = ret && (param = next_tok(NULL, CONTROLLER_MENU_PARAM_DELIMITER, &item_state)) &&
sscanf(param, "%d", &id);
ret = ret && (text = next_tok(NULL, CONTROLLER_MENU_PARAM_DELIMITER, &item_state));
ret = ret && (param = next_tok(NULL, CONTROLLER_MENU_PARAM_DELIMITER, &item_state)) &&
sscanf(param, "%d", &flags);
if (!ret) {
DBG(0, "item parsing failed %s", item);
break;
}
DBG(0, "parent_id=%d, id=%d, text=%s, flags=%d", parent_id, id, text, flags);
AutoRef<Menu> sub_menu((*menu)->find_sub(parent_id));
if (!(ret = !!*sub_menu)) {
DBG(0, "submenu not found %s", item);
break;
}
if (flags & CONTROLLER_MENU_FLAGS_SEPARATOR) {
(*sub_menu)->add_separator();
} else if (flags & CONTROLLER_MENU_FLAGS_POPUP) {
AutoRef<Menu> sub(new Menu((*app_menu)->get_target(), text, id));
(*sub_menu)->add_sub(sub.release());
} else {
state = 0;
if (flags & (CONTROLLER_MENU_FLAGS_DISABLED | CONTROLLER_MENU_FLAGS_GRAYED)) {
state |= Menu::MENU_ITEM_STATE_DIM;
}
if (flags & CONTROLLER_MENU_FLAGS_CHECKED) {
state |= Menu::MENU_ITEM_STATE_CHECKED;
}
if (id >= SPICE_MENU_INTERNAL_ID_BASE) {
id = ((id - SPICE_MENU_INTERNAL_ID_BASE) >> SPICE_MENU_INTERNAL_ID_SHIFT) + 1;
} else {
id = _handler->get_controller_menu_item_id(_opaque, id);
}
(*sub_menu)->add_command(text, id, state);
}
item = next_tok(next_item, CONTROLLER_MENU_ITEM_DELIMITER, &item_state);
}
if (ret) {
_handler->set_menu(*menu);
}
return ret;
}
bool ControllerConnection::set_multi_val(uint32_t op, char* multi_val)
{
CmdLineParser parser("", false);
int id = CmdLineParser::OPTION_FIRST_AVAILABLE;
char* argv[] = {NULL, (char*)"--set", multi_val};
char* val;
ASSERT(_handler);
parser.add(id, "set", "none", "none", true);
parser.set_multi(id, ',');
parser.begin(3, argv);
if (parser.get_option(&val) != id) {
return false;
}
switch (op) {
case CONTROLLER_SECURE_CHANNELS:
_handler->set_channels_security(parser, true, val, "Controller");
break;
case CONTROLLER_DISABLE_CHANNELS:
_handler->set_enable_channels(parser, false, val, "Controller");
break;
default:
DBG(0, "unsupported op %u", op);
return false;
}
return true;
}

View File

@ -1,119 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CONTROLLER_MENU
#define _H_CONTROLLER_MENU
#include "named_pipe.h"
#include "threads.h"
class ControllerConnection;
struct ControllerInit;
struct ControllerMsg;
class CmdLineParser;
class Menu;
class ControllerInterface {
public:
virtual ~ControllerInterface() {}
virtual bool connect(const std::string& host, int port, int sport,
const std::string& password) = 0;
virtual void set_title(const std::string& title) = 0;
virtual void set_auto_display_res(bool auto_display_res) = 0;
virtual void show_me(bool full_screen) = 0;
virtual void hide_me() = 0;
virtual bool set_channels_security(CmdLineParser& parser, bool on, char *val,
const char* arg0) = 0;
virtual bool set_enable_channels(CmdLineParser& parser, bool enable, char *val,
const char* arg0) = 0;
virtual bool set_connection_ciphers(const char* ciphers, const char* arg0) = 0;
virtual bool set_ca_file(const char* ca_file, const char* arg0) = 0;
virtual bool set_host_cert_subject(const char* subject, const char* arg0) = 0;
virtual void set_hotkeys(const std::string& hotkeys) = 0;
virtual int get_controller_menu_item_id(int32_t opaque_conn_ref, uint32_t id) = 0;
virtual void clear_menu_items(int32_t opaque_conn_ref) = 0;
virtual Menu* get_app_menu() = 0;
virtual void set_menu(Menu* menu) = 0;
virtual void delete_menu() = 0;
#ifdef USE_SMARTCARD
virtual void enable_smartcard(bool enable) = 0;
#endif
};
class Controller : public NamedPipe::ListenerInterface {
public:
Controller(ControllerInterface *handler);
virtual ~Controller();
Controller* ref() { _refs++; return this;}
void unref() { if (!--_refs) delete this;}
virtual NamedPipe::ConnectionInterface &create();
bool set_exclusive(bool exclusive);
void add_connection(NamedPipe::ConnectionRef conn_ref, ControllerConnection *conn);
void remove_connection(NamedPipe::ConnectionRef conn_ref);
void on_command(NamedPipe::ConnectionRef conn_ref, int32_t id);
private:
ControllerInterface *_handler;
std::map<NamedPipe::ConnectionRef, ControllerConnection*> _connections;
NamedPipe::ListenerRef _pipe;
bool _exclusive;
int _refs;
};
#define CONTROLLER_BUF_SIZE 4096
class ControllerConnection : public NamedPipe::ConnectionInterface {
public:
ControllerConnection(ControllerInterface *handler, Controller& parent);
virtual ~ControllerConnection();
virtual void bind(NamedPipe::ConnectionRef conn_ref);
virtual void on_data();
bool write_msg(const void *buf, int len);
void reset_handler() { _handler = NULL;}
private:
bool read_msgs();
bool handle_init(ControllerInit *init);
bool handle_message(ControllerMsg *hdr);
bool create_menu(char* resource);
bool set_multi_val(uint32_t op, char* multi_val);
private:
ControllerInterface *_handler;
Controller& _parent;
bool _initialized;
int _write_pending;
uint8_t *_write_pos;
uint8_t *_read_pos;
uint8_t _write_buf[CONTROLLER_BUF_SIZE];
uint8_t _read_buf[CONTROLLER_BUF_SIZE];
RecurciveMutex _write_lock;
std::string _host;
std::string _password;
int _port;
int _sport;
bool _full_screen;
bool _auto_display_res;
};
#endif

View File

@ -1,115 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "cursor.h"
#include "utils.h"
#include "debug.h"
CursorData::CursorData(SpiceCursor& cursor, int data_size)
: _atomic (1)
, _header (cursor.header)
, _data (NULL)
, _opaque (NULL)
, _local_cursor (NULL)
{
int expected_size = 0;
switch (cursor.header.type) {
case SPICE_CURSOR_TYPE_ALPHA:
expected_size = (_header.width << 2) * _header.height;
break;
case SPICE_CURSOR_TYPE_MONO:
expected_size = (SPICE_ALIGN(_header.width, 8) >> 2) * _header.height;
break;
case SPICE_CURSOR_TYPE_COLOR4:
expected_size = (SPICE_ALIGN(_header.width, 2) >> 1) * _header.height;
expected_size += (SPICE_ALIGN(_header.width, 8) >> 3) * _header.height;
expected_size += 16 * sizeof(uint32_t);
break;
case SPICE_CURSOR_TYPE_COLOR8:
expected_size = _header.width * _header.height;
expected_size += (SPICE_ALIGN(_header.width, 8) >> 3) * _header.height;
expected_size += 256 * sizeof(uint32_t);
break;
case SPICE_CURSOR_TYPE_COLOR16:
expected_size = (_header.width << 1) * _header.height;
expected_size += (SPICE_ALIGN(_header.width, 8) >> 3) * _header.height;
break;
case SPICE_CURSOR_TYPE_COLOR24:
expected_size = (_header.width * 3) * _header.height;
expected_size += (SPICE_ALIGN(_header.width, 8) >> 3) * _header.height;
break;
case SPICE_CURSOR_TYPE_COLOR32:
expected_size = (_header.width << 2) * _header.height;
expected_size += (SPICE_ALIGN(_header.width, 8) >> 3) * _header.height;
break;
}
if (data_size < expected_size) {
THROW("access violation 0x%" PRIuPTR " %u", (uintptr_t)cursor.data, expected_size);
}
_data = new uint8_t[expected_size];
memcpy(_data, cursor.data, expected_size);
}
void CursorData::set_local(LocalCursor* local_cursor)
{
ASSERT(!_local_cursor);
if (local_cursor) {
_local_cursor = local_cursor->ref();
}
}
CursorData::~CursorData()
{
if (_local_cursor) {
_local_cursor->unref();
}
delete _opaque;
delete[] _data;
}
int LocalCursor::get_size_bits(const SpiceCursorHeader& header, int& size)
{
switch (header.type) {
case SPICE_CURSOR_TYPE_ALPHA:
case SPICE_CURSOR_TYPE_COLOR32:
size = (header.width << 2) * header.height;
return 32;
case SPICE_CURSOR_TYPE_MONO:
size = (SPICE_ALIGN(header.width, 8) >> 3) * header.height;
return 1;
case SPICE_CURSOR_TYPE_COLOR4:
size = (SPICE_ALIGN(header.width, 2) >> 1) * header.height;
return 4;
case SPICE_CURSOR_TYPE_COLOR8:
size = header.width * header.height;
return 8;
case SPICE_CURSOR_TYPE_COLOR16:
size = (header.width << 1) * header.height;
return 16;
case SPICE_CURSOR_TYPE_COLOR24:
size = (header.width * 3) * header.height;
return 24;
default:
return 0;
}
}

View File

@ -1,72 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CURSOR_
#define _H_CURSOR_
#include "common/messages.h"
#include "threads.h"
#include "red_window_p.h"
class CursorOpaque {
public:
CursorOpaque() {}
virtual ~CursorOpaque() {}
};
class LocalCursor;
class CursorData {
public:
CursorData(SpiceCursor& cursor, int data_size);
CursorData *ref() { ++_atomic; return this;}
void unref() {if (--_atomic == 0) delete this;}
void set_opaque(CursorOpaque* opaque) { delete _opaque; _opaque = opaque;}
CursorOpaque* get_opaque() { return _opaque;}
void set_local(LocalCursor* local_cursor);
LocalCursor* get_local() { return _local_cursor;}
const SpiceCursorHeader& header() const { return _header;}
const uint8_t* data() const { return _data;}
private:
~CursorData();
private:
AtomicCount _atomic;
SpiceCursorHeader _header;
uint8_t* _data;
CursorOpaque* _opaque;
LocalCursor* _local_cursor;
};
class LocalCursor {
public:
LocalCursor(): _atomic (1) {}
virtual ~LocalCursor() {}
virtual void set(Window window) {}
LocalCursor* ref() { ++_atomic; return this;}
void unref() { if (--_atomic == 0) delete this;}
protected:
static int get_size_bits(const SpiceCursorHeader& header, int &size);
private:
AtomicCount _atomic;
};
#endif

View File

@ -1,670 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common/rect.h"
#include "common.h"
#include "cursor_channel.h"
#include "display_channel.h"
#include "cursor.h"
#include "red_client.h"
#include "application.h"
#include "debug.h"
#include "utils.h"
#include "screen.h"
#include "red_pixmap_sw.h"
static inline uint8_t revers_bits(uint8_t byte)
{
uint8_t ret = 0;
int i;
for (i = 0; i < 4; i++) {
int shift = 7 - i * 2;
ret |= (byte & (1 << i)) << shift;
ret |= (byte & (0x80 >> i)) >> shift;
}
return ret;
}
class NaitivCursor: public CursorOpaque {
public:
virtual void draw(RedDrawable& dest, int x, int y, const SpiceRect& area) = 0;
};
class AlphaCursor: public NaitivCursor {
public:
AlphaCursor(const SpiceCursorHeader& header, const uint8_t* data);
virtual void draw(RedDrawable& dest, int x, int y, const SpiceRect& area);
private:
std::auto_ptr<RedPixmap> _pixmap;
};
class MonoCursor: public NaitivCursor {
public:
MonoCursor(const SpiceCursorHeader& header, const uint8_t* data);
virtual void draw(RedDrawable& dest, int x, int y, const SpiceRect& area);
private:
std::auto_ptr<RedPixmap> _pixmap;
int _height;
};
class UnsupportedCursor: public NaitivCursor {
public:
UnsupportedCursor(const SpiceCursorHeader& header);
virtual void draw(RedDrawable& dest, int x, int y, const SpiceRect& area);
private:
int _hot_x;
int _hot_y;
};
UnsupportedCursor::UnsupportedCursor(const SpiceCursorHeader& header)
: _hot_x (header.hot_spot_x)
, _hot_y (header.hot_spot_y)
{
LOG_WARN("Unsupported cursor %hu", header.type);
}
void UnsupportedCursor::draw(RedDrawable& dest, int x, int y, const SpiceRect& area)
{
SpiceRect dest_area;
SpiceRect rect;
dest_area.left = area.left;
dest_area.right = area.right;
dest_area.top = area.top;
dest_area.bottom = area.bottom;
rect.left = x + _hot_x - 2;
rect.right = rect.left + 8;
rect.top = y + _hot_y - 2;
rect.bottom = rect.top + 8;
rect_sect(rect, dest_area);
dest.fill_rect(rect, rgb32_make(0xf8, 0xf1, 0xb8));
rect.left = x + _hot_x - 1;
rect.right = rect.left + 6;
rect.top = y + _hot_y - 1;
rect.bottom = rect.top + 6;
rect_sect(rect, dest_area);
dest.frame_rect(rect, rgb32_make(0, 0, 0));
}
AlphaCursor::AlphaCursor(const SpiceCursorHeader& header, const uint8_t* data)
: _pixmap (new RedPixmapSw(header.width, header.height,
RedDrawable::ARGB32, true, NULL))
{
int stride = _pixmap->get_stride();
uint8_t* dest = _pixmap->get_data();
int line_size = header.width * sizeof(uint32_t);
for (int i = 0; i < header.height; i++, data += line_size, dest += stride) {
memcpy(dest, data, line_size);
}
}
void AlphaCursor::draw(RedDrawable& dest, int x, int y, const SpiceRect& area)
{
dest.blend_pixels(*_pixmap, area.left - x, area.top - y, area);
}
MonoCursor::MonoCursor(const SpiceCursorHeader& header, const uint8_t* data)
: _pixmap (NULL)
, _height (header.height)
{
_pixmap.reset(new RedPixmapSw(header.width, _height * 2, RedDrawable::A1,
true, NULL));
int dest_stride = _pixmap->get_stride();
uint8_t *dest_line = _pixmap->get_data();
int src_stride = SPICE_ALIGN(header.width, 8) >> 3;
const uint8_t* src_line = data;
const uint8_t* end_line = src_line + _pixmap->get_height() * src_stride;
if (_pixmap->is_big_endian_bits()) {
for (; src_line < end_line; src_line += src_stride, dest_line += dest_stride) {
memcpy(dest_line, src_line, src_stride);
}
} else {
for (; src_line < end_line; src_line += src_stride, dest_line += dest_stride) {
for (int i = 0; i < src_stride; i++) {
dest_line[i] = revers_bits(src_line[i]);
}
}
}
}
void MonoCursor::draw(RedDrawable& dest, int x, int y, const SpiceRect& area)
{
dest.combine_pixels(*_pixmap, area.left - x, area.top - y, area, RedDrawable::OP_AND);
dest.combine_pixels(*_pixmap, area.left - x, area.top - y + _height, area, RedDrawable::OP_XOR);
}
class ColorCursor: public NaitivCursor {
public:
ColorCursor(const SpiceCursorHeader& header);
virtual void draw(RedDrawable& dest, int x, int y, const SpiceRect& area);
protected:
void init_pixels(const SpiceCursorHeader& header, const uint8_t* _pixels, const uint8_t *and_mask);
virtual uint32_t get_pixel_color(const uint8_t *data, int row, int col) = 0;
private:
std::auto_ptr<RedPixmap> _pixmap;
std::auto_ptr<RedPixmap> _invers;
};
ColorCursor::ColorCursor(const SpiceCursorHeader& header)
: _pixmap (new RedPixmapSw(header.width, header.height,
RedDrawable::ARGB32, true, NULL))
, _invers (NULL)
{
_invers.reset(new RedPixmapSw(header.width, header.height, RedDrawable::A1,
true, NULL));
}
void ColorCursor::init_pixels(const SpiceCursorHeader& header, const uint8_t* pixels,
const uint8_t *and_mask)
{
int mask_stride = SPICE_ALIGN(header.width, 8) / 8;
int invers_stride = _invers->get_stride();
int pixmap_stride = _pixmap->get_stride();
uint8_t *_pixmap_line = _pixmap->get_data();
uint8_t* invers_line = _invers->get_data();
bool be_bits = _invers->is_big_endian_bits();
memset(invers_line, 0, header.height * invers_stride);
for (int i = 0; i < header.height; i++, and_mask += mask_stride, invers_line += invers_stride,
_pixmap_line += pixmap_stride) {
uint32_t *line_32 = (uint32_t *)_pixmap_line;
for (int j = 0; j < header.width; j++) {
uint32_t pixel_val = get_pixel_color(pixels, i, j);
int and_val = test_bit_be(and_mask, j);
if ((pixel_val & 0x00ffffff) == 0 && and_val) {
line_32[j] = 0;
} else if ((pixel_val & 0x00ffffff) == 0x00ffffff && and_val) {
line_32[j] = 0;
if (be_bits) {
set_bit_be(invers_line, j);
} else {
set_bit(invers_line, j);
}
} else {
line_32[j] = pixel_val | 0xff000000;
}
}
}
}
void ColorCursor::draw(RedDrawable& dest, int x, int y, const SpiceRect& area)
{
dest.blend_pixels(*_pixmap, area.left - x, area.top - y, area);
dest.combine_pixels(*_invers, area.left - x, area.top - y, area, RedDrawable::OP_XOR);
}
class ColorCursor32: public ColorCursor {
public:
ColorCursor32(const SpiceCursorHeader& header, const uint8_t* data)
: ColorCursor(header)
, _src_stride (header.width * sizeof(uint32_t))
{
init_pixels(header, data, data + _src_stride * header.height);
}
private:
uint32_t get_pixel_color(const uint8_t *data, int row, int col)
{
return *((uint32_t *)(data + row * _src_stride) + col);
}
private:
int _src_stride;
};
class ColorCursor16: public ColorCursor {
public:
ColorCursor16(const SpiceCursorHeader& header, const uint8_t* data)
: ColorCursor(header)
, _src_stride (header.width * sizeof(uint16_t))
{
init_pixels(header, data, data + _src_stride * header.height);
}
private:
uint32_t get_pixel_color(const uint8_t *data, int row, int col)
{
uint32_t pix = *((uint16_t*)(data + row * _src_stride) + col);
return ((pix & 0x1f) << 3) | ((pix & 0x3e0) << 6) | ((pix & 0x7c00) << 9);
}
private:
int _src_stride;
};
class ColorCursor4: public ColorCursor {
public:
ColorCursor4(const SpiceCursorHeader& header, const uint8_t* data)
: ColorCursor(header)
, _src_stride (SPICE_ALIGN(header.width, 2) >> 1)
, _palette ((uint32_t*)(data + _src_stride * header.height))
{
init_pixels(header, data, (uint8_t*)(_palette + 16));
}
private:
uint32_t get_pixel_color(const uint8_t *data, int row, int col)
{
data += _src_stride * row + (col >> 1);
return (col & 1) ? _palette[*data & 0x0f] : _palette[*data >> 4];
}
private:
int _src_stride;
uint32_t* _palette;
};
class AttachDispayEvent: public Event {
public:
AttachDispayEvent(CursorChannel& channel)
: _channel (channel)
{
}
class UpdateDisplayChannel: public ForEachChannelFunc {
public:
UpdateDisplayChannel(CursorChannel& channel)
: _channel (channel)
{
}
virtual bool operator() (RedChannel& channel)
{
if (channel.get_type() != SPICE_CHANNEL_DISPLAY ||
channel.get_id() != _channel.get_id()) {
return true;
}
_channel.attach_display(&static_cast<DisplayChannel&>(channel));
return false;
}
private:
CursorChannel& _channel;
};
virtual void response(AbstractProcessLoop& events_loop)
{
UpdateDisplayChannel func(_channel);
_channel.get_client().for_each_channel(func);
}
private:
CursorChannel& _channel;
};
class CursorUpdateEvent: public Event {
public:
CursorUpdateEvent(CursorChannel& channel)
: _channel (channel)
{
}
virtual void response(AbstractProcessLoop& events_loop)
{
DisplayChannel* display_channel = _channel._display_channel;
if (!display_channel) {
return;
}
Lock lock(_channel._update_lock);
if (_channel._cursor_visible) {
display_channel->set_cursor(_channel._cursor);
return;
}
display_channel->hide_cursor();
}
private:
CursorChannel& _channel;
};
class CursorHandler: public MessageHandlerImp<CursorChannel, SPICE_CHANNEL_CURSOR> {
public:
CursorHandler(CursorChannel& channel)
: MessageHandlerImp<CursorChannel, SPICE_CHANNEL_CURSOR>(channel) {}
};
CursorChannel::CursorChannel(RedClient& client, uint32_t id)
: RedChannel(client, SPICE_CHANNEL_CURSOR, id, new CursorHandler(*this))
, ScreenLayer(SCREEN_LAYER_CURSOR, false)
, _cursor (NULL)
, _cursor_visible (false)
, _display_channel (NULL)
{
CursorHandler* handler = static_cast<CursorHandler*>(get_message_handler());
handler->set_handler(SPICE_MSG_MIGRATE, &CursorChannel::handle_migrate);
handler->set_handler(SPICE_MSG_SET_ACK, &CursorChannel::handle_set_ack);
handler->set_handler(SPICE_MSG_PING, &CursorChannel::handle_ping);
handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &CursorChannel::handle_wait_for_channels);
handler->set_handler(SPICE_MSG_DISCONNECTING, &CursorChannel::handle_disconnect);
handler->set_handler(SPICE_MSG_NOTIFY, &CursorChannel::handle_notify);
handler->set_handler(SPICE_MSG_CURSOR_INIT, &CursorChannel::handle_init);
handler->set_handler(SPICE_MSG_CURSOR_RESET, &CursorChannel::handle_reset);
handler->set_handler(SPICE_MSG_CURSOR_SET, &CursorChannel::handle_cursor_set);
handler->set_handler(SPICE_MSG_CURSOR_MOVE, &CursorChannel::handle_cursor_move);
handler->set_handler(SPICE_MSG_CURSOR_HIDE, &CursorChannel::handle_cursor_hide);
handler->set_handler(SPICE_MSG_CURSOR_TRAIL, &CursorChannel::handle_cursor_trail);
handler->set_handler(SPICE_MSG_CURSOR_INVAL_ONE, &CursorChannel::handle_inval_one);
handler->set_handler(SPICE_MSG_CURSOR_INVAL_ALL, &CursorChannel::handle_inval_all);
}
CursorChannel::~CursorChannel()
{
ASSERT(!_cursor);
}
void CursorChannel::on_connect()
{
AutoRef<AttachDispayEvent> attach_event(new AttachDispayEvent(*this));
get_client().push_event(*attach_event);
}
void CursorChannel::on_disconnect()
{
remove_cursor();
_cursor_cache.clear();
AutoRef<SyncEvent> sync_event(new SyncEvent());
get_client().push_event(*sync_event);
(*sync_event)->wait();
detach_from_screen(get_client().get_application());
}
void CursorChannel::update_display_cursor()
{
if (!_display_channel) {
return;
}
AutoRef<CursorUpdateEvent> update_event(new CursorUpdateEvent(*this));
get_client().push_event(*update_event);
}
void CursorChannel::remove_cursor()
{
Lock lock(_update_lock);
_cursor_visible = false;
if (_cursor) {
_cursor->unref();
_cursor = NULL;
}
lock.unlock();
clear_area();
update_display_cursor();
}
void CursorChannel::copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc)
{
pixman_box32_t *rects;
int num_rects;
Lock lock(_update_lock);
if (!_cursor_visible) {
return;
}
rects = pixman_region32_rectangles((pixman_region32_t *)&dest_region, &num_rects);
for (int i = 0; i < num_rects; i++) {
SpiceRect r;
r.left = rects[i].x1;
r.top = rects[i].y1;
r.right = rects[i].x2;
r.bottom = rects[i].y2;
ASSERT(_cursor && _cursor->get_opaque());
((NaitivCursor*)_cursor->get_opaque())->draw(dest_dc, _cursor_rect.left, _cursor_rect.top,
r);
}
}
void CursorChannel::create_native_cursor(CursorData* cursor)
{
CursorOpaque* native_cursor = cursor->get_opaque();
if (native_cursor) {
return;
}
switch (cursor->header().type) {
case SPICE_CURSOR_TYPE_ALPHA:
native_cursor = new AlphaCursor(cursor->header(), cursor->data());
break;
case SPICE_CURSOR_TYPE_COLOR32:
native_cursor = new ColorCursor32(cursor->header(), cursor->data());
break;
case SPICE_CURSOR_TYPE_MONO:
native_cursor = new MonoCursor(cursor->header(), cursor->data());
break;
case SPICE_CURSOR_TYPE_COLOR4:
native_cursor = new ColorCursor4(cursor->header(), cursor->data());
break;
case SPICE_CURSOR_TYPE_COLOR8:
native_cursor = new UnsupportedCursor(cursor->header());
break;
case SPICE_CURSOR_TYPE_COLOR16:
native_cursor = new ColorCursor16(cursor->header(), cursor->data());
break;
case SPICE_CURSOR_TYPE_COLOR24:
native_cursor = new UnsupportedCursor(cursor->header());
break;
default:
THROW("invalid cursor type");
}
cursor->set_opaque(native_cursor);
}
void CursorChannel::set_cursor(SpiceCursor& red_cursor, int x, int y, bool visible)
{
CursorData *cursor;
if (red_cursor.flags & SPICE_CURSOR_FLAGS_NONE) {
remove_cursor();
return;
}
if (red_cursor.flags & SPICE_CURSOR_FLAGS_FROM_CACHE) {
cursor = _cursor_cache.get(red_cursor.header.unique);
} else {
cursor = new CursorData(red_cursor, red_cursor.data_size);
if (red_cursor.flags & SPICE_CURSOR_FLAGS_CACHE_ME) {
ASSERT(red_cursor.header.unique);
_cursor_cache.add(red_cursor.header.unique, cursor);
}
}
AutoRef<CursorData> cursor_ref(cursor);
create_native_cursor(cursor);
Lock lock(_update_lock);
_hot_pos.x = x;
_hot_pos.y = y;
_cursor_visible = visible;
_cursor_rect.left = x - cursor->header().hot_spot_x;
_cursor_rect.right = _cursor_rect.left + cursor->header().width;
_cursor_rect.top = y - cursor->header().hot_spot_y;
_cursor_rect.bottom = _cursor_rect.top + cursor->header().height;
if (_cursor) {
_cursor->unref();
}
_cursor = cursor->ref();
lock.unlock();
update_display_cursor();
if (get_client().get_mouse_mode() == SPICE_MOUSE_MODE_SERVER) {
if (_cursor_visible) {
set_rect_area(_cursor_rect);
} else {
clear_area();
}
}
}
void CursorChannel::attach_display(DisplayChannel* channel)
{
if (_display_channel) {
return;
}
_display_channel = channel;
Lock lock(_update_lock);
if (!_cursor_visible) {
return;
}
_display_channel->set_cursor(_cursor);
}
void CursorChannel::detach_display()
{
_display_channel = NULL;
}
void CursorChannel::handle_init(RedPeer::InMessage *message)
{
SpiceMsgCursorInit *init = (SpiceMsgCursorInit*)message->data();
attach_to_screen(get_client().get_application(), get_id());
remove_cursor();
_cursor_cache.clear();
set_cursor(init->cursor, init->position.x,
init->position.y, init->visible != 0);
}
void CursorChannel::handle_reset(RedPeer::InMessage *message)
{
remove_cursor();
detach_from_screen(get_client().get_application());
_cursor_cache.clear();
}
void CursorChannel::handle_cursor_set(RedPeer::InMessage* message)
{
SpiceMsgCursorSet* set = (SpiceMsgCursorSet*)message->data();
set_cursor(set->cursor, set->position.x,
set->position.y, set->visible != 0);
}
void CursorChannel::handle_cursor_move(RedPeer::InMessage* message)
{
SpiceMsgCursorMove* move = (SpiceMsgCursorMove*)message->data();
if (!_cursor) {
return;
}
Lock lock(_update_lock);
_cursor_visible = true;
int dx = move->position.x - _hot_pos.x;
int dy = move->position.y - _hot_pos.y;
_hot_pos.x += dx;
_hot_pos.y += dy;
_cursor_rect.left += dx;
_cursor_rect.right += dx;
_cursor_rect.top += dy;
_cursor_rect.bottom += dy;
lock.unlock();
if (get_client().get_mouse_mode() == SPICE_MOUSE_MODE_SERVER) {
set_rect_area(_cursor_rect);
return;
}
update_display_cursor();
}
void CursorChannel::handle_cursor_hide(RedPeer::InMessage* message)
{
Lock lock(_update_lock);
_cursor_visible = false;
update_display_cursor();
if (get_client().get_mouse_mode() == SPICE_MOUSE_MODE_SERVER) {
clear_area();
}
}
void CursorChannel::handle_cursor_trail(RedPeer::InMessage* message)
{
SpiceMsgCursorTrail* trail = (SpiceMsgCursorTrail*)message->data();
DBG(0, "length %u frequency %u", trail->length, trail->frequency)
}
void CursorChannel::handle_inval_one(RedPeer::InMessage* message)
{
SpiceMsgDisplayInvalOne* inval = (SpiceMsgDisplayInvalOne*)message->data();
_cursor_cache.remove(inval->id);
}
void CursorChannel::handle_inval_all(RedPeer::InMessage* message)
{
_cursor_cache.clear();
}
void CursorChannel::on_mouse_mode_change()
{
Lock lock(_update_lock);
if (get_client().get_mouse_mode() == SPICE_MOUSE_MODE_CLIENT) {
clear_area();
return;
}
if (_cursor_visible) {
set_rect_area(_cursor_rect);
}
}
class CursorFactory: public ChannelFactory {
public:
CursorFactory() : ChannelFactory(SPICE_CHANNEL_CURSOR) {}
virtual RedChannel* construct(RedClient& client, uint32_t id)
{
return new CursorChannel(client, id);
}
};
static CursorFactory factory;
ChannelFactory& CursorChannel::Factory()
{
return factory;
}

View File

@ -1,93 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CURSOR_CHANNEL
#define _H_CURSOR_CHANNEL
#include "red_channel.h"
#include "cache.hpp"
#include "cursor.h"
#include "screen_layer.h"
class ChannelFactory;
class CursorChannel;
class DisplayChannel;
class CursorCacheTreat {
public:
static inline CursorData* get(CursorData* cursor)
{
return cursor->ref();
}
static inline void release(CursorData* cursor)
{
cursor->unref();
}
static const char* name() { return "cursor";}
};
typedef Cache<CursorData, CursorCacheTreat, 1024> CursorCache;
class CursorChannel: public RedChannel, public ScreenLayer {
public:
CursorChannel(RedClient& client, uint32_t id);
virtual ~CursorChannel();
static ChannelFactory& Factory();
void on_mouse_mode_change();
void attach_display(DisplayChannel* channel);
void detach_display();
protected:
virtual void on_connect();
virtual void on_disconnect();
private:
static void create_native_cursor(CursorData* cursor);
void update_display_cursor();
void set_cursor(SpiceCursor& red_cursor, int x, int y, bool visible);
void remove_cursor();
virtual void copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc);
void handle_init(RedPeer::InMessage* message);
void handle_reset(RedPeer::InMessage* message);
void handle_cursor_set(RedPeer::InMessage* message);
void handle_cursor_move(RedPeer::InMessage* message);
void handle_cursor_hide(RedPeer::InMessage* message);
void handle_cursor_trail(RedPeer::InMessage* message);
void handle_inval_one(RedPeer::InMessage* message);
void handle_inval_all(RedPeer::InMessage* message);
friend class AttachDispayEvent;
friend class CursorUpdateEvent;
private:
CursorCache _cursor_cache;
CursorData* _cursor;
SpicePoint _hot_pos;
SpiceRect _cursor_rect;
Mutex _update_lock;
bool _cursor_visible;
DisplayChannel* _display_channel;
};
#endif

View File

@ -1,92 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_DEBUG
#define _H_DEBUG
#include <stdlib.h>
#include <sstream>
#include "platform.h"
#ifdef WIN32
#define snprintf _snprintf
#endif
#define ON_PANIC() ::abort()
#ifdef RED_DEBUG
#ifdef WIN32
#define ASSERTBREAK DebugBreak()
#else
#define ASSERTBREAK ::abort()
#endif
#define ASSERT(x) if (!(x)) { \
printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); \
ASSERTBREAK; \
}
#else
#define ASSERT(cond)
#endif
enum {
LOG_DEBUG,
LOG_INFO,
LOG_WARN,
LOG_ERROR,
LOG_FATAL
};
void spice_log(unsigned int type, const char *function, const char *format, ...);
void spice_log_cleanup(void);
#ifdef __GNUC__
#define SPICE_FUNC_NAME __PRETTY_FUNCTION__
#else
#define SPICE_FUNC_NAME __FUNCTION__
#endif
#define LOG(type, format, ...) spice_log(type, SPICE_FUNC_NAME, format, ## __VA_ARGS__)
#define LOG_INFO(format, ...) LOG(LOG_INFO, format, ## __VA_ARGS__)
#define LOG_WARN(format, ...) LOG(LOG_WARN, format, ## __VA_ARGS__)
#define LOG_ERROR(format, ...) LOG(LOG_ERROR, format, ## __VA_ARGS__)
#define PANIC(format, ...) { \
LOG(LOG_FATAL, format, ## __VA_ARGS__); \
ON_PANIC(); \
}
#define PANIC_ON(x) if ((x)) { \
LOG(LOG_FATAL, "%s panic %s\n", __FUNCTION__, #x); \
ON_PANIC(); \
}
#define DBGLEVEL 1000
#define DBG(level, format, ...) { \
if (level <= DBGLEVEL) { \
LOG(LOG_DEBUG, format, ## __VA_ARGS__); \
} \
}
#endif // _H_DEBUG

File diff suppressed because it is too large Load Diff

View File

@ -1,247 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_DISPLAY_CHANNEL
#define _H_DISPLAY_CHANNEL
#include "common/region.h"
#include "common.h"
#include "canvas.h"
#include "red_channel.h"
#include "cache.hpp"
#include "screen_layer.h"
#include "process_loop.h"
#ifdef USE_OPENGL
#include "red_pixmap_gl.h"
#endif
#include "glz_decoder_window.h"
class RedScreen;
class ChannelFactory;
class VideoStream;
class DisplayChannel;
class CursorData;
class InputsChannel;
class StreamsTrigger: public EventSources::Trigger {
public:
StreamsTrigger(DisplayChannel& channel);
virtual void on_event();
private:
DisplayChannel& _channel;
};
#ifdef USE_OPENGL
class GLInterruptRecreate: public EventSources::Trigger {
public:
GLInterruptRecreate(DisplayChannel& channel);
virtual void trigger();
virtual void on_event();
private:
DisplayChannel& _channel;
Mutex _lock;
Condition _cond;
};
#endif
class InterruptUpdate: public EventSources::Trigger {
public:
InterruptUpdate(DisplayChannel& channel);
virtual void on_event();
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:
DisplayChannel(RedClient& client, uint32_t id,
PixmapCache& pixmap_cache, GlzDecoderWindow& glz_window);
virtual ~DisplayChannel();
virtual void copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc);
virtual void copy_pixels(const QRegion& dest_region, const PixmapHeader &dest);
#ifdef USE_OPENGL
virtual void recreate_ogl_context();
virtual void recreate_ogl_context_interrupt();
virtual void pre_migrate();
virtual void post_migrate();
#endif
virtual void update_interrupt();
void set_cursor(CursorData* cursor);
void hide_cursor();
void set_capture_mode(bool on);
virtual bool pointer_test(int x, int y);
virtual void on_pointer_enter(int x, int y, unsigned int buttons_state);
virtual void on_pointer_motion(int x, int y, unsigned int buttons_state);
virtual void on_pointer_leave();
virtual void on_mouse_button_press(int button, int buttons_state);
virtual void on_mouse_button_release(int button, int buttons_state);
void attach_inputs(InputsChannel* inputs_channel);
void detach_inputs();
static ChannelFactory& Factory();
protected:
virtual void on_connect();
virtual void on_disconnect();
virtual void on_disconnect_mig_src();
private:
void set_draw_handlers();
void clear_draw_handlers();
bool create_sw_canvas(int surface_id, int width, int height, uint32_t format);
#ifdef USE_OPENGL
bool create_ogl_canvas(int surface_id, int width, int height, uint32_t format, bool recreate,
RenderType rendertype);
#endif
#ifdef WIN32
bool create_gdi_canvas(int surface_id, int width, int height, uint32_t format);
#endif
void destroy_canvas(int surface_id);
void create_canvas(int surface_id, const std::vector<int>& canvas_type, int width, int height,
uint32_t format);
void destroy_streams();
void update_cursor();
void create_primary_surface(int width, int height, uint32_t format);
void create_surface(int surface_id, int width, int height, uint32_t format);
void destroy_primary_surface();
void destroy_surface(int surface_id);
void destroy_all_surfaces();
void do_destroy_all_surfaces();
void destroy_off_screen_surfaces();
void do_destroy_off_screen_surfaces();
void handle_mode(RedPeer::InMessage* message);
void handle_mark(RedPeer::InMessage* message);
void handle_reset(RedPeer::InMessage* message);
void handle_inval_list(RedPeer::InMessage* message);
void handle_inval_all_pixmaps(RedPeer::InMessage* message);
void handle_inval_palette(RedPeer::InMessage* message);
void handle_inval_all_palettes(RedPeer::InMessage* message);
void handle_copy_bits(RedPeer::InMessage* message);
void handle_stream_create(RedPeer::InMessage* message);
void handle_stream_data(RedPeer::InMessage* message);
void handle_stream_clip(RedPeer::InMessage* message);
void handle_stream_destroy(RedPeer::InMessage* message);
void handle_stream_destroy_all(RedPeer::InMessage* message);
void handle_surface_create(RedPeer::InMessage* message);
void handle_surface_destroy(RedPeer::InMessage* message);
void handle_draw_fill(RedPeer::InMessage* message);
void handle_draw_opaque(RedPeer::InMessage* message);
void handle_draw_copy(RedPeer::InMessage* message);
void handle_draw_blend(RedPeer::InMessage* message);
void handle_draw_blackness(RedPeer::InMessage* message);
void handle_draw_whiteness(RedPeer::InMessage* message);
void handle_draw_invers(RedPeer::InMessage* message);
void handle_draw_rop3(RedPeer::InMessage* message);
void handle_draw_stroke(RedPeer::InMessage* message);
void handle_draw_text(RedPeer::InMessage* message);
void handle_draw_transparent(RedPeer::InMessage* message);
void handle_draw_alpha_blend(RedPeer::InMessage* message);
void handle_draw_composite(RedPeer::InMessage* message);
void on_streams_trigger();
virtual void on_update_completion(uint64_t mark);
void streams_time();
void activate_streams_timer();
void stream_update_request(uint32_t update_time);
void reset_screen();
void clear(bool destroy_primary = true);
static void set_clip_rects(const SpiceClip& clip, uint32_t& num_clip_rects, SpiceRect*& clip_rects);
private:
SurfacesCache _surfaces_cache;
SurfacesCache _swsurfaces_cache;
PixmapCache& _pixmap_cache;
PaletteCache _palette_cache;
GlzDecoderWindow& _glz_window;
bool _mark;
int _x_res;
int _y_res;
uint32_t _format;
#ifdef USE_OPENGL
RenderType _rendertype;
#endif
#ifndef RED64
Mutex _mark_lock;
#endif
uint64_t _update_mark;
Mutex _streams_lock;
Mutex _timer_lock;
AutoRef<StreamsTimer> _streams_timer;
uint32_t _next_timer_time;
AutoRef<CursorData> _cursor;
bool _cursor_visibal;
bool _active_pointer;
bool _capture_mouse_mode;
InputsChannel* _inputs_channel;
SpicePoint _pointer_pos;
int _buttons_state;
std::vector<VideoStream*> _streams;
VideoStream* _active_streams;
StreamsTrigger _streams_trigger;
#ifdef USE_OPENGL
GLInterruptRecreate _gl_interrupt_recreate;
#endif
InterruptUpdate _interrupt_update;
bool _mig_wait_primary;
bool _check_diff;
friend class SetModeEvent;
friend class CreatePrimarySurfaceEvent;
friend class DestroyPrimarySurfaceEvent;
friend class CreateSurfaceEvent;
friend class DestroySurfaceEvent;
friend class DestroyAllSurfacesEvent;
friend class ActivateTimerEvent;
friend class VideoStream;
friend class StreamsTrigger;
friend class GLInterupt;
friend class StreamsTimer;
friend class AttachChannelsEvent;
friend class DetachChannelsEvent;
friend class MigPrimarySurfaceTimer;
};
#endif

View File

@ -1,94 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; 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

View File

@ -1,376 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "foreign_menu.h"
#include <spice/foreign_menu_prot.h>
#include "menu.h"
#include "utils.h"
#include "debug.h"
#include "platform.h"
#define PIPE_NAME_MAX_LEN 50
#ifdef WIN32
#define PIPE_NAME "SpiceForeignMenu-%lu"
#elif defined(__i386__) || __SIZEOF_LONG__ == 4
#define PIPE_NAME "/tmp/SpiceForeignMenu-%llu.uds"
#else
#define PIPE_NAME "/tmp/SpiceForeignMenu-%lu.uds"
#endif
ForeignMenu::ForeignMenu(ForeignMenuInterface *handler, bool active)
: _handler (handler)
, _active (active)
, _refs (1)
{
char pipe_name[PIPE_NAME_MAX_LEN];
ASSERT(_handler != NULL);
#ifndef WIN32
const char *p_socket = getenv("SPICE_FOREIGN_MENU_SOCKET");
if (p_socket) {
LOG_INFO("Creating a foreign menu connection %s", p_socket);
_foreign_menu = NamedPipe::create(p_socket, *this);
} else
#endif
{
snprintf(pipe_name, PIPE_NAME_MAX_LEN, PIPE_NAME, Platform::get_process_id());
LOG_INFO("Creating a foreign menu connection %s", pipe_name);
_foreign_menu = NamedPipe::create(pipe_name, *this);
}
if (!_foreign_menu) {
LOG_ERROR("Failed to create a foreign menu connection");
}
}
ForeignMenu::~ForeignMenu()
{
std::map<NamedPipe::ConnectionRef, ForeignMenuConnection*>::const_iterator conn;
for (conn = _connections.begin(); conn != _connections.end(); ++conn) {
conn->second->reset_handler();
delete conn->second;
}
if (_foreign_menu) {
NamedPipe::destroy(_foreign_menu);
}
}
NamedPipe::ConnectionInterface& ForeignMenu::create()
{
ForeignMenuConnection *conn = new ForeignMenuConnection(_handler, *this);
if (conn == NULL) {
throw Exception("Error allocating a new foreign menu connection");
}
return *conn;
}
void ForeignMenu::add_connection(NamedPipe::ConnectionRef conn_ref, ForeignMenuConnection *conn)
{
_connections[conn_ref] = conn;
if (_active) {
send_active_state(conn, FOREIGN_MENU_APP_ACTIVATED);
}
conn->on_data();
}
void ForeignMenu::remove_connection(NamedPipe::ConnectionRef conn_ref)
{
ForeignMenuConnection *conn = _connections[conn_ref];
_connections.erase(conn_ref);
delete conn;
}
void ForeignMenu::add_sub_menus()
{
std::map<NamedPipe::ConnectionRef, ForeignMenuConnection*>::const_iterator conn;
for (conn = _connections.begin(); conn != _connections.end(); ++conn) {
conn->second->add_sub_menu();
}
}
void ForeignMenu::on_command(NamedPipe::ConnectionRef conn_ref, int32_t id)
{
ForeignMenuConnection *conn = _connections[conn_ref];
FrgMenuEvent msg;
ASSERT(conn);
msg.base.id = FOREIGN_MENU_ITEM_EVENT;
msg.base.size = sizeof(FrgMenuEvent);
msg.id = id;
msg.action = FOREIGN_MENU_EVENT_CLICK;
conn->write_msg(&msg.base, msg.base.size);
}
void ForeignMenu::on_activate()
{
std::map<NamedPipe::ConnectionRef, ForeignMenuConnection*>::const_iterator conn;
_active = true;
for (conn = _connections.begin(); conn != _connections.end(); ++conn) {
send_active_state(conn->second, FOREIGN_MENU_APP_ACTIVATED);
}
}
void ForeignMenu::on_deactivate()
{
std::map<NamedPipe::ConnectionRef, ForeignMenuConnection*>::const_iterator conn;
_active = false;
for (conn = _connections.begin(); conn != _connections.end(); ++conn) {
send_active_state(conn->second, FOREIGN_MENU_APP_DEACTIVATED);
}
}
void ForeignMenu::send_active_state(ForeignMenuConnection *conn, int32_t cmd)
{
FrgMenuMsg msg;
ASSERT(conn != NULL);
msg.id = cmd;
msg.size = sizeof(FrgMenuMsg);
conn->write_msg(&msg, msg.size);
}
ForeignMenuConnection::ForeignMenuConnection(ForeignMenuInterface *handler, ForeignMenu& parent)
: _handler (handler)
, _parent (parent)
, _sub_menu (NULL)
, _initialized (false)
, _write_pending (0)
, _write_pos (_write_buf)
, _read_pos (_read_buf)
{
}
ForeignMenuConnection::~ForeignMenuConnection()
{
if (_opaque != NamedPipe::INVALID_CONNECTION) {
NamedPipe::destroy_connection(_opaque);
}
if (_handler) {
AutoRef<Menu> app_menu(_handler->get_app_menu());
(*app_menu)->remove_sub(_sub_menu);
_handler->update_menu();
_handler->clear_menu_items(_opaque);
}
if (_sub_menu) {
_sub_menu->unref();
}
}
void ForeignMenuConnection::bind(NamedPipe::ConnectionRef conn_ref)
{
_opaque = conn_ref;
_parent.add_connection(conn_ref, this);
}
void ForeignMenuConnection::on_data()
{
if (_write_pending) {
LOG_INFO("Resume pending write %d", _write_pending);
if (!write_msg(_write_pos, _write_pending)) {
return;
}
}
while (read_msgs());
}
bool ForeignMenuConnection::read_msgs()
{
uint8_t *pos = _read_buf;
size_t nread = _read_pos - _read_buf;
int32_t size;
ASSERT(_handler);
ASSERT(_opaque != NamedPipe::INVALID_CONNECTION);
size = NamedPipe::read(_opaque, (uint8_t*)_read_pos, sizeof(_read_buf) - nread);
if (size == 0) {
return false;
} else if (size < 0) {
LOG_ERROR("Error reading from named pipe %d", size);
_parent.remove_connection(_opaque);
return false;
}
nread += size;
while (nread > 0) {
if (!_initialized && nread >= sizeof(FrgMenuInitHeader)) {
FrgMenuInitHeader *init = (FrgMenuInitHeader *)pos;
if (init->magic != FOREIGN_MENU_MAGIC || init->version != FOREIGN_MENU_VERSION) {
LOG_ERROR("Bad foreign menu init, magic=0x%x version=%u", init->magic,
init->version);
_parent.remove_connection(_opaque);
return false;
}
if (nread < init->size) {
break;
}
if (!handle_init((FrgMenuInit*)init)) {
_parent.remove_connection(_opaque);
return false;
}
nread -= init->size;
pos += init->size;
_initialized = true;
}
if (!_initialized || nread < sizeof(FrgMenuMsg)) {
break;
}
FrgMenuMsg *hdr = (FrgMenuMsg *)pos;
if (hdr->size < sizeof(FrgMenuMsg)) {
LOG_ERROR("Bad foreign menu message, size=%u", hdr->size);
_parent.remove_connection(_opaque);
return false;
}
if (nread < hdr->size) {
break;
}
handle_message(hdr);
nread -= hdr->size;
pos += hdr->size;
}
if (nread > 0 && pos != _read_buf) {
memmove(_read_buf, pos, nread);
}
_read_pos = _read_buf + nread;
return true;
}
bool ForeignMenuConnection::write_msg(const void *buf, int len)
{
RecurciveLock lock(_write_lock);
uint8_t *pos;
int32_t written = 0;
ASSERT(_opaque != NamedPipe::INVALID_CONNECTION);
if (_write_pending && buf != _write_pos) {
if ((_write_pos + _write_pending + len > _write_buf + sizeof(_write_buf)) &&
!write_msg(_write_pos, _write_pending)) {
return false;
}
if (_write_pending) {
if (_write_pos + _write_pending + len > _write_buf + sizeof(_write_buf)) {
DBG(0, "Dropping message, due to insufficient space in write buffer");
return true;
}
memcpy(_write_pos + _write_pending, buf, len);
_write_pending += len;
}
}
pos = (uint8_t*)buf;
while (len && (written = NamedPipe::write(_opaque, pos, len)) > 0) {
pos += written;
len -= written;
}
if (len && written == 0) {
if (_write_pending) {
_write_pos = pos;
} else {
_write_pos = _write_buf;
memcpy(_write_buf, pos, len);
}
_write_pending = len;
} else if (written < 0) {
LOG_ERROR("Error writing to named pipe %d", written);
_parent.remove_connection(_opaque);
return false;
} else {
_write_pending = 0;
}
return true;
}
bool ForeignMenuConnection::handle_init(FrgMenuInit *init)
{
std::string title = "Untitled";
ASSERT(_handler);
if (_sub_menu) {
LOG_ERROR("Foreign menu already initialized");
return false;
}
if (init->credentials != 0) {
LOG_ERROR("Foreign menu has wrong credentials 0x%x", init->credentials);
return false;
}
if (init->base.size > offsetof(FrgMenuInit, title)) {
((char*)init)[init->base.size - 1] = '\0';
title = (char*)init->title;
}
_sub_menu = new Menu((CommandTarget&)*_handler, title);
add_sub_menu();
_handler->update_menu();
return true;
}
void ForeignMenuConnection::add_sub_menu()
{
if (_sub_menu) {
AutoRef<Menu> app_menu(_handler->get_app_menu());
(*app_menu)->add_sub(_sub_menu);
}
}
bool ForeignMenuConnection::handle_message(FrgMenuMsg *hdr)
{
ASSERT(_sub_menu);
ASSERT(_handler);
switch (hdr->id) {
case FOREIGN_MENU_SET_TITLE:
((char*)hdr)[hdr->size - 1] = '\0';
_sub_menu->set_name((char*)((FrgMenuSetTitle*)hdr)->string);
break;
case FOREIGN_MENU_ADD_ITEM: {
FrgMenuAddItem *msg = (FrgMenuAddItem*)hdr;
((char*)hdr)[hdr->size - 1] = '\0';
int id = _handler->get_foreign_menu_item_id(_opaque, msg->id);
_sub_menu->add_command((char*)msg->string, id, get_item_state(msg->type));
break;
}
case FOREIGN_MENU_REMOVE_ITEM: {
int id = _handler->get_foreign_menu_item_id(_opaque, ((FrgMenuRmItem*)hdr)->id);
_sub_menu->remove_command(id);
_handler->remove_menu_item(id);
break;
}
case FOREIGN_MENU_CLEAR:
_sub_menu->clear();
_handler->clear_menu_items(_opaque);
break;
case FOREIGN_MENU_MODIFY_ITEM:
default:
LOG_ERROR("Ignoring an unknown foreign menu identifier %u", hdr->id);
return false;
}
_handler->update_menu();
return true;
}
int ForeignMenuConnection::get_item_state(int item_type)
{
int state = 0;
if (item_type & FOREIGN_MENU_ITEM_TYPE_CHECKED) {
state |= Menu::MENU_ITEM_STATE_CHECKED;
}
if (item_type & FOREIGN_MENU_ITEM_TYPE_DIM) {
state |= Menu::MENU_ITEM_STATE_DIM;
}
return state;
}

View File

@ -1,98 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_FOREIGN_MENU
#define _H_FOREIGN_MENU
#include "named_pipe.h"
#include "menu.h"
class ForeignMenuConnection;
struct FrgMenuInit;
struct FrgMenuMsg;
class ForeignMenuInterface : public CommandTarget {
public:
virtual ~ForeignMenuInterface() {}
virtual int get_foreign_menu_item_id(int32_t opaque_conn_ref, uint32_t msg_id) = 0;
virtual void clear_menu_items(int32_t opaque_conn_ref) = 0;
virtual void remove_menu_item(int item_id) = 0;
virtual Menu* get_app_menu() = 0;
virtual void update_menu() = 0;
};
class ForeignMenu : public NamedPipe::ListenerInterface {
public:
ForeignMenu(ForeignMenuInterface *handler, bool active = false);
virtual ~ForeignMenu();
ForeignMenu* ref() { _refs++; return this;}
void unref() { if (!--_refs) delete this;}
virtual NamedPipe::ConnectionInterface &create();
void add_connection(NamedPipe::ConnectionRef conn_ref, ForeignMenuConnection *conn);
void remove_connection(NamedPipe::ConnectionRef conn_ref);
void add_sub_menus();
void on_command(NamedPipe::ConnectionRef conn_ref, int32_t id);
void on_activate();
void on_deactivate();
private:
void send_active_state(ForeignMenuConnection *conn, int32_t cmd);
private:
ForeignMenuInterface *_handler;
std::map<NamedPipe::ConnectionRef, ForeignMenuConnection*> _connections;
NamedPipe::ListenerRef _foreign_menu;
bool _active;
int _refs;
};
#define FOREIGN_MENU_BUF_SIZE 4096
class ForeignMenuConnection : public NamedPipe::ConnectionInterface {
public:
ForeignMenuConnection(ForeignMenuInterface *handler, ForeignMenu& parent);
virtual ~ForeignMenuConnection();
virtual void bind(NamedPipe::ConnectionRef conn_ref);
virtual void on_data();
bool write_msg(const void *buf, int len);
void reset_handler() { _handler = NULL;}
void add_sub_menu();
private:
bool read_msgs();
bool handle_init(FrgMenuInit *init);
bool handle_message(FrgMenuMsg *hdr);
int get_item_state(int item_type);
private:
ForeignMenuInterface *_handler;
ForeignMenu& _parent;
Menu* _sub_menu;
bool _initialized;
int _write_pending;
uint8_t *_write_pos;
uint8_t *_read_pos;
uint8_t _write_buf[FOREIGN_MENU_BUF_SIZE];
uint8_t _read_buf[FOREIGN_MENU_BUF_SIZE];
RecurciveMutex _write_lock;
};
#endif

View File

@ -1,337 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
// External defines: PLT, RGBX/PLTXX/ALPHA, TO_RGB32.
// If PLT4/1 and TO_RGB32 are defined, we need CAST_PLT_DISTANCE (
// because then the number of pixels differ from the units used in the compression)
/*
For each output pixel type the following macros are defined:
OUT_PIXEL - the output pixel type
COPY_PIXEL(p, out) - assigns the pixel to the place pointed by out and
increases out. Used in RLE.
Need special handling because in alpha we copy only
the pad byte.
COPY_REF_PIXEL(ref, out) - copies the pixel pointed by ref to the pixel pointed by out.
Increases ref and out.
COPY_COMP_PIXEL(encoder, out) - copies pixel from the compressed buffer to the decompressed
buffer. Increases out.
*/
#if !defined(LZ_RGB_ALPHA)
#define COPY_PIXEL(p, out) (*(out++) = p)
#define COPY_REF_PIXEL(ref, out) (*(out++) = *(ref++))
#endif
// decompressing plt to plt
#ifdef LZ_PLT
#ifndef TO_RGB32
#define OUT_PIXEL one_byte_pixel_t
#define FNAME(name) glz_plt_##name
#define COPY_COMP_PIXEL(in, out) {(out)->a = *(in++); out++;}
#else // TO_RGB32
#define OUT_PIXEL rgb32_pixel_t
#define COPY_PLT_ENTRY(ent, out) {\
(out)->b = ent; (out)->g = (ent >> 8); (out)->r = (ent >> 16); (out)->pad = 0;}
#ifdef PLT8
#define FNAME(name) glz_plt8_to_rgb32_##name
#define COPY_COMP_PIXEL(in, out, palette) { \
uint32_t rgb = palette->ents[*(in++)]; \
COPY_PLT_ENTRY(rgb, out); \
out++; \
}
#elif defined(PLT4_BE)
#define FNAME(name) glz_plt4_be_to_rgb32_##name
#define COPY_COMP_PIXEL(in, out, palette){ \
uint8_t byte = *(in++); \
uint32_t rgb = palette->ents[((byte >> 4) & 0x0f) % (palette->num_ents)]; \
COPY_PLT_ENTRY(rgb, out); \
out++; \
rgb = palette->ents[(byte & 0x0f) % (palette->num_ents)]; \
COPY_PLT_ENTRY(rgb, out); \
out++; \
}
#define CAST_PLT_DISTANCE(dist) (dist*2)
#elif defined(PLT4_LE)
#define FNAME(name) glz_plt4_le_to_rgb32_##name
#define COPY_COMP_PIXEL(in, out, palette){ \
uint8_t byte = *(in++); \
uint32_t rgb = palette->ents[(byte & 0x0f) % (palette->num_ents)]; \
COPY_PLT_ENTRY(rgb, out); \
out++; \
rgb = palette->ents[((byte >> 4) & 0x0f) % (palette->num_ents)]; \
COPY_PLT_ENTRY(rgb, out); \
out++; \
}
#define CAST_PLT_DISTANCE(dist) (dist*2)
#elif defined(PLT1_BE) // TODO store palette entries for direct access
#define FNAME(name) glz_plt1_be_to_rgb32_##name
#define COPY_COMP_PIXEL(in, out, palette){ \
uint8_t byte = *(in++); \
int i; \
uint32_t fore = palette->ents[1]; \
uint32_t back = palette->ents[0]; \
for (i = 7; i >= 0; i--) \
{ \
if ((byte >> i) & 1) { \
COPY_PLT_ENTRY(fore, out); \
} else { \
COPY_PLT_ENTRY(back, out); \
} \
out++; \
} \
}
#define CAST_PLT_DISTANCE(dist) (dist*8)
#elif defined(PLT1_LE)
#define FNAME(name) glz_plt1_le_to_rgb32_##name
#define COPY_COMP_PIXEL(in, out, palette){ \
uint8_t byte = *(in++); \
int i; \
uint32_t fore = palette->ents[1]; \
uint32_t back = palette->ents[0]; \
for (i = 0; i < 8; i++) \
{ \
if ((byte >> i) & 1) { \
COPY_PLT_ENTRY(fore, out); \
} else { \
COPY_PLT_ENTRY(back, out); \
} \
out++; \
} \
}
#define CAST_PLT_DISTANCE(dist) (dist*8)
#endif // PLT Type
#endif // TO_RGB32
#endif
#ifdef LZ_RGB16
#ifndef TO_RGB32
#define OUT_PIXEL rgb16_pixel_t
#define FNAME(name) glz_rgb16_##name
#define COPY_COMP_PIXEL(in, out) {*out = (*(in++)) << 8; *out |= *(in++); out++;}
#else
#define OUT_PIXEL rgb32_pixel_t
#define FNAME(name) glz_rgb16_to_rgb32_##name
#define COPY_COMP_PIXEL(in, out) {out->r = *(in++); out->b= *(in++); \
out->g = (((out->r) << 6) | ((out->b) >> 2)) & ~0x07; \
out->g |= (out->g >> 5); \
out->r = ((out->r << 1) & ~0x07) | ((out->r >> 4) & 0x07) ; \
out->b = (out->b << 3) | ((out->b >> 2) & 0x07); \
out->pad = 0; \
out++; \
}
#endif
#endif
#ifdef LZ_RGB24
#define OUT_PIXEL rgb24_pixel_t
#define FNAME(name) glz_rgb24_##name
#define COPY_COMP_PIXEL(in, out) { \
out->b = *(in++); \
out->g = *(in++); \
out->r = *(in++); \
out++; \
}
#endif
#ifdef LZ_RGB32
#define OUT_PIXEL rgb32_pixel_t
#define FNAME(name) glz_rgb32_##name
#define COPY_COMP_PIXEL(in, out) { \
out->b = *(in++); \
out->g = *(in++); \
out->r = *(in++); \
out->pad = 0; \
out++; \
}
#endif
#ifdef LZ_RGB_ALPHA
#define OUT_PIXEL rgb32_pixel_t
#define FNAME(name) glz_rgb_alpha_##name
#define COPY_PIXEL(p, out) {out->pad = p.pad; out++;}
#define COPY_REF_PIXEL(ref, out) {out->pad = ref->pad; out++; ref++;}
#define COPY_COMP_PIXEL(in, out) {out->pad = *(in++); out++;}
#endif
// TODO: separate into routines that decode to dist,len. and to a routine that
// actually copies the data.
/* returns num of bytes read from in buf.
size should be in PIXEL */
static size_t FNAME(decode)(GlzDecoderWindow &window, uint8_t* in_buf,
uint8_t *out_buf, int size,
DecodedImageWinId image_win_id, SpicePalette *plt,
GlzDecoderDebug &debug_calls)
{
uint8_t *ip = in_buf;
OUT_PIXEL *out_pix_buf = (OUT_PIXEL *)out_buf;
OUT_PIXEL *op = out_pix_buf;
OUT_PIXEL *op_limit = out_pix_buf + size;
uint32_t ctrl = *(ip++);
int loop = true;
do {
if (ctrl >= MAX_COPY) { // reference (dictionary/RLE)
OUT_PIXEL *ref = op;
uint32_t len = ctrl >> 5;
uint8_t pixel_flag = (ctrl >> 4) & 0x01;
uint32_t pixel_ofs = (ctrl & 0x0f);
uint8_t image_flag;
uint32_t image_dist;
/* retrieving the referenced images, the offset of the first pixel,
and the match length */
uint8_t code;
//len--; // TODO: why do we do this?
if (len == 7) { // match length is bigger than 7
do {
code = *(ip++);
len += code;
} while (code == 255); // remaining of len
}
code = *(ip++);
pixel_ofs += (code << 4);
code = *(ip++);
image_flag = (code >> 6) & 0x03;
if (!pixel_flag) { // short pixel offset
image_dist = code & 0x3f;
for (int i = 0; i < image_flag; i++) {
code = *(ip++);
image_dist += (code << (6 + (8 * i)));
}
} else {
pixel_flag = (code >> 5) & 0x01;
pixel_ofs += (code & 0x1f) << 12;
image_dist = 0;
for (int i = 0; i < image_flag; i++) {
code = *(ip++);
image_dist += (code << 8 * i);
}
if (pixel_flag) { // very long pixel offset
code = *(ip++);
pixel_ofs += code << 17;
}
}
#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
len += 2; // length is biased by 2 (fixing bias)
#elif defined(LZ_RGB16)
len += 1; // length is biased by 1 (fixing bias)
#endif
if (!image_dist) {
pixel_ofs += 1; // offset is biased by 1 (fixing bias)
}
#if defined(TO_RGB32)
#if defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || defined(PLT1_LE)
pixel_ofs = CAST_PLT_DISTANCE(pixel_ofs);
len = CAST_PLT_DISTANCE(len);
#endif
#endif
if (!image_dist) { // reference is inside the same image
ref -= pixel_ofs;
GLZ_ASSERT(debug_calls, ref + len <= op_limit);
GLZ_ASSERT(debug_calls, ref >= out_pix_buf);
} else {
ref = (OUT_PIXEL *)window.get_ref_pixel(image_win_id, image_dist,
pixel_ofs);
}
GLZ_ASSERT(debug_calls, op + len <= op_limit);
/* copying the match*/
if (ref == (op - 1)) { // run (this will never be called in PLT4/1_TO_RGB because the
// number of pixel copied is larger then one...
/* optimize copy for a run */
OUT_PIXEL b = *ref;
for (; len; --len) {
COPY_PIXEL(b, op);
GLZ_ASSERT(debug_calls, op <= op_limit);
}
} else {
for (; len; --len) {
COPY_REF_PIXEL(ref, op);
GLZ_ASSERT(debug_calls, op <= op_limit);
}
}
} else { // copy
ctrl++; // copy count is biased by 1
#if defined(TO_RGB32) && (defined(PLT4_BE) || defined(PLT4_LE) || defined(PLT1_BE) || \
defined(PLT1_LE))
GLZ_ASSERT(debug_calls, op + CAST_PLT_DISTANCE(ctrl) <= op_limit);
#else
GLZ_ASSERT(debug_calls, op + ctrl <= op_limit);
#endif
#if defined(TO_RGB32) && defined(LZ_PLT)
GLZ_ASSERT(debug_calls, plt);
COPY_COMP_PIXEL(ip, op, plt);
#else
COPY_COMP_PIXEL(ip, op);
#endif
GLZ_ASSERT(debug_calls, op <= op_limit);
for (--ctrl; ctrl; ctrl--) {
#if defined(TO_RGB32) && defined(LZ_PLT)
GLZ_ASSERT(debug_calls, plt);
COPY_COMP_PIXEL(ip, op, plt);
#else
COPY_COMP_PIXEL(ip, op);
#endif
GLZ_ASSERT(debug_calls, op <= op_limit);
}
} // END REF/COPY
if (LZ_EXPECT_CONDITIONAL(op < op_limit)) {
ctrl = *(ip++);
} else {
loop = false;
}
} while (LZ_EXPECT_CONDITIONAL(loop));
return (ip - in_buf);
}
#undef LZ_PLT
#undef PLT8
#undef PLT4_BE
#undef PLT4_LE
#undef PLT1_BE
#undef PLT1_LE
#undef LZ_RGB16
#undef LZ_RGB24
#undef LZ_RGB32
#undef LZ_RGB_ALPHA
#undef TO_RGB32
#undef OUT_PIXEL
#undef FNAME
#undef COPY_PIXEL
#undef COPY_REF_PIXEL
#undef COPY_COMP_PIXEL
#undef COPY_PLT_ENTRY
#undef CAST_PLT_DISTANCE

View File

@ -1,64 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_GLZ_DECODED_IMAGE
#define _H_GLZ_DECODED_IMAGE
#include "common.h"
#include "glz_decoder_config.h"
/*
This class represents an image the lz window holds. It is created after the decoding of the
image is completed, and destroyed when it exits the window.
*/
class GlzDecodedImage {
public:
GlzDecodedImage(uint64_t id, uint64_t win_head_id, uint8_t *data, int size,
int bytes_per_pixel)
: _id (id)
, _win_head_id (win_head_id)
, _data (data)
, _bytes_per_pixel (bytes_per_pixel)
, _size (size) {}
virtual ~GlzDecodedImage() {}
uint8_t *get_data() {return _data;}
uint8_t *get_pixel_ref(int offset); // palette pix_id = byte count
uint64_t get_id() {return _id;}
uint64_t get_window_head_id() {return _win_head_id;}
int get_size() {return _size;}
protected:
uint64_t _id;
uint64_t _win_head_id;
uint8_t *_data;
int _bytes_per_pixel; // if image is with palette pixel=byte
int _size; // number of pixels
};
inline uint8_t* GlzDecodedImage::get_pixel_ref(int offset)
{
if (!_data) {
return NULL;
} else {
return (_data + (offset * _bytes_per_pixel));
}
}
#endif

View File

@ -1,301 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "glz_decoder_config.h"
#include "glz_decoder.h"
static void op_decode (SpiceGlzDecoder *decoder,
uint8_t *data,
SpicePalette *plt,
void *usr_data)
{
GlzDecoder* _decoder = static_cast<GlzDecoder*>(decoder);
_decoder->decode(data, plt, usr_data);
}
GlzDecoder::GlzDecoder(GlzDecoderWindow &images_window,
GlzDecodeHandler &usr_handler, GlzDecoderDebug &debug_calls)
: _images_window (images_window)
, _usr_handler (usr_handler)
, _debug_calls (debug_calls)
{
static SpiceGlzDecoderOps decoder_ops = {
op_decode,
};
ops = &decoder_ops;
}
GlzDecoder::~GlzDecoder()
{
}
void GlzDecoder::decode_header()
{
uint32_t magic;
int version;
uint8_t tmp;
int stride;
magic = decode_32();
if (magic != LZ_MAGIC) {
_debug_calls.warn(std::string("bad magic\n"));
}
version = decode_32();
if (version != LZ_VERSION) {
_debug_calls.warn(std::string("bad version\n"));
}
tmp = *(_in_now++);
_image.type = (LzImageType)(tmp & LZ_IMAGE_TYPE_MASK);
_image.top_down = (tmp >> LZ_IMAGE_TYPE_LOG) ? true : false;
_image.width = decode_32();
_image.height = decode_32();
stride = decode_32();
if (IS_IMAGE_TYPE_PLT[_image.type]) {
_image.gross_pixels = stride * PLT_PIXELS_PER_BYTE[_image.type] * _image.height;
} else {
_image.gross_pixels = _image.width * _image.height;
}
_image.id = decode_64();
_image.win_head_dist = decode_32();
}
inline uint32_t GlzDecoder::decode_32()
{
uint32_t word = 0;
word |= *(_in_now++);
word <<= 8;
word |= *(_in_now++);
word <<= 8;
word |= *(_in_now++);
word <<= 8;
word |= *(_in_now++);
return word;
}
inline uint64_t GlzDecoder::decode_64()
{
uint64_t long_word = decode_32();
long_word <<= 32;
long_word |= decode_32();
return long_word;
}
// TODO: the code is historically c based. Consider transforming to c++ and use templates
// - but be sure it won't make it slower!
/*
* Give hints to the compiler for branch prediction optimization.
*/
#if defined(__GNUC__) && (__GNUC__ > 2)
#define LZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
#define LZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
#else
#define LZ_EXPECT_CONDITIONAL(c) (c)
#define LZ_UNEXPECT_CONDITIONAL(c) (c)
#endif
#ifdef __GNUC__
#define ATTR_PACKED __attribute__ ((__packed__))
#else
#define ATTR_PACKED
#pragma pack(push)
#pragma pack(1)
#endif
/* the palette images will be treated as one byte pixels. Their width should be transformed
accordingly.
*/
typedef struct ATTR_PACKED one_byte_pixel_t {
uint8_t a;
} one_byte_pixel_t;
typedef struct ATTR_PACKED rgb32_pixel_t {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t pad;
} rgb32_pixel_t;
typedef struct ATTR_PACKED rgb24_pixel_t {
uint8_t b;
uint8_t g;
uint8_t r;
} rgb24_pixel_t;
typedef uint16_t rgb16_pixel_t;
#ifndef __GNUC__
#pragma pack(pop)
#endif
#undef ATTR_PACKED
#define LZ_PLT
#include "glz_decode_tmpl.c"
#define LZ_PLT
#define PLT8
#define TO_RGB32
#include "glz_decode_tmpl.c"
#define LZ_PLT
#define PLT4_BE
#define TO_RGB32
#include "glz_decode_tmpl.c"
#define LZ_PLT
#define PLT4_LE
#define TO_RGB32
#include "glz_decode_tmpl.c"
#define LZ_PLT
#define PLT1_BE
#define TO_RGB32
#include "glz_decode_tmpl.c"
#define LZ_PLT
#define PLT1_LE
#define TO_RGB32
#include "glz_decode_tmpl.c"
#define LZ_RGB16
#include "glz_decode_tmpl.c"
#define LZ_RGB16
#define TO_RGB32
#include "glz_decode_tmpl.c"
#define LZ_RGB24
#include "glz_decode_tmpl.c"
#define LZ_RGB32
#include "glz_decode_tmpl.c"
#define LZ_RGB_ALPHA
#include "glz_decode_tmpl.c"
#undef LZ_UNEXPECT_CONDITIONAL
#undef LZ_EXPECT_CONDITIONAL
typedef size_t (*decode_function)(GlzDecoderWindow &window, uint8_t* in_buf,
uint8_t *out_buf, int size,
DecodedImageWinId image_win_id, SpicePalette *plt,
GlzDecoderDebug &debug_calls);
// ordered according to LZ_IMAGE_TYPE
const decode_function DECODE_TO_RGB32[] = {
NULL,
glz_plt1_le_to_rgb32_decode,
glz_plt1_be_to_rgb32_decode,
glz_plt4_le_to_rgb32_decode,
glz_plt4_be_to_rgb32_decode,
glz_plt8_to_rgb32_decode,
glz_rgb16_to_rgb32_decode,
glz_rgb32_decode,
glz_rgb32_decode,
glz_rgb32_decode
};
const decode_function DECODE_TO_SAME[] = {
NULL,
glz_plt_decode,
glz_plt_decode,
glz_plt_decode,
glz_plt_decode,
glz_plt_decode,
glz_rgb16_decode,
glz_rgb24_decode,
glz_rgb32_decode,
glz_rgb32_decode
};
void GlzDecoder::decode(uint8_t *data, SpicePalette *palette, void *opaque_usr_info)
{
DecodedImageWinId image_window_id;
GlzDecodedImage *decoded_image;
size_t n_in_bytes_decoded;
int bytes_per_pixel;
LzImageType decoded_type;
_in_start = data;
_in_now = data;
decode_header();
#ifdef GLZ_DECODE_TO_RGB32
bytes_per_pixel = 4;
if (_image.type == LZ_IMAGE_TYPE_RGBA) {
decoded_type = LZ_IMAGE_TYPE_RGBA;
} else {
decoded_type = LZ_IMAGE_TYPE_RGB32;
}
#else
if (IS_IMAGE_TYPE_PLT[_image.type]) {
GLZ_ASSERT(_debug_calls, !(_image.gross_pixels % PLT_PIXELS_PER_BYTE[_image.type]));
}
bytes_per_pixel = RGB_BYTES_PER_PIXEL[_image.type];
decoded_type = _image.type;
#endif
image_window_id = _images_window.pre_decode(_image.id, _image.id - _image.win_head_dist);
decoded_image = _usr_handler.alloc_image(opaque_usr_info, _image.id,
_image.id - _image.win_head_dist,
decoded_type, _image.width, _image.height,
_image.gross_pixels, bytes_per_pixel,
_image.top_down);
_image.data = decoded_image->get_data();
// decode_by_type
#ifdef GLZ_DECODE_TO_RGB32
n_in_bytes_decoded = DECODE_TO_RGB32[_image.type](_images_window, _in_now, _image.data,
_image.gross_pixels, image_window_id,
palette, _debug_calls);
#else
n_in_bytes_decoded = DECODE_TO_SAME[_image.type](_images_window, _in_now, _image.data,
IS_IMAGE_TYPE_PLT[_image.type] ?
_image.gross_pixels /
PLT_PIXELS_PER_BYTE[_image.type] :
_image.gross_pixels,
image_window_id, palette, _debug_calls);
#endif
_in_now += n_in_bytes_decoded;
if (_image.type == LZ_IMAGE_TYPE_RGBA) {
glz_rgb_alpha_decode(_images_window, _in_now, _image.data,
_image.gross_pixels, image_window_id, palette, _debug_calls);
}
_images_window.post_decode(decoded_image);
}

View File

@ -1,84 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_GLZ_DECODER
#define _H_GLZ_DECODER
#include "common/lz_common.h"
#include "glz_decoder_config.h"
#include "glz_decoder_window.h"
#include "red_canvas_base.h"
class GlzDecodeHandler {
public:
GlzDecodeHandler() {}
virtual ~GlzDecodeHandler() {}
/* Called by the decoder before the image decoding is starts. The
user of the decoder should create GlzDecodedImage instance.
If resources should be released when the image exits the Glz window,
it should be handled in the instance dtor.
opaque_usr_info: the data sent when GlzDecoder::decode was called
gross_pixels : number of pixels when considering the whole stride*/
virtual GlzDecodedImage *alloc_image(void *opaque_usr_info, uint64_t image_id,
uint64_t image_win_head_id, LzImageType type,
int width, int height, int gross_pixels,
int n_bytes_per_pixel, bool top_down) = 0;
};
/*
This class implements the lz decoding algorithm
*/
class GlzDecoder : public SpiceGlzDecoder
{
public:
GlzDecoder(GlzDecoderWindow &images_window, GlzDecodeHandler &usr_handler,
GlzDecoderDebug &debug_calls);
virtual ~GlzDecoder();
/* Decodes the data and afterwards calls GlzDecodeHandler::handle_decoded_image */
void decode(uint8_t *data, SpicePalette *palette, void *opaque_usr_info);
private:
void decode_header();
uint32_t decode_32();
uint64_t decode_64();
private:
GlzDecoderWindow &_images_window;
GlzDecodeHandler &_usr_handler;
GlzDecoderDebug &_debug_calls;
uint8_t *_in_now;
uint8_t *_in_start;
struct {
uint64_t id;
LzImageType type;
int width;
int height;
int gross_pixels;
bool top_down;
int win_head_dist;
uint8_t *data;
} _image;
};
#endif // _H_GLZ_DECODER

View File

@ -1,64 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_GLZ_DECODER_CONFIG
#define _H_GLZ_DECODER_CONFIG
#include <exception>
#include <sstream>
#include <stdio.h>
#include <spice/types.h>
#include <spice/macros.h>
#include "common/lz_common.h"
class GlzException: public std::exception {
public:
GlzException(const std::string& str) : _mess (str) {}
virtual ~GlzException() throw () {}
virtual const char* what() const throw () {return _mess.c_str();}
private:
std::string _mess;
};
class GlzDecoderDebug {
public:
virtual ~GlzDecoderDebug() {}
virtual void error(const std::string& str) = 0;
virtual void warn(const std::string& str) = 0;
virtual void info(const std::string& str) = 0;
};
#ifdef RED_DEBUG
#define GLZ_ASSERT(debug, x) { \
if (!(x)) { \
std::ostringstream os; \
os << __FUNCTION__ << ": ASSERT " << #x << " failed\n"; \
(debug).error(os.str()); \
} \
}
#else
#define GLZ_ASSERT(debug, x)
#endif
#define GLZ_DECODE_TO_RGB32
#endif //_H_GLZ_DECODER_CONFIG

View File

@ -1,329 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "glz_decoder_window.h"
#include "utils.h"
#define INIT_IMAGES_CAPACITY 100
#define WIN_REALLOC_FACTOR 1.5
GlzDecoderWindow::GlzDecoderWindow(GlzDecoderDebug &debug_calls)
: _aborting (false)
, _debug_calls (debug_calls)
{
_images_capacity = INIT_IMAGES_CAPACITY;
_images = new GlzDecodedImage*[_images_capacity];
if (!_images) {
_debug_calls.error(std::string("failed allocating images\n"));
}
memset(_images, 0, sizeof(GlzDecodedImage*) * _images_capacity);
init();
}
GlzDecoderWindow::~GlzDecoderWindow()
{
clear();
delete[] _images;
}
DecodedImageWinId GlzDecoderWindow::pre_decode(uint64_t image_id, uint64_t relative_head_id)
{
DecodedImageWinId image_win_id = pre_decode_update_window(image_id, relative_head_id);
pre_decode_finalize();
return image_win_id;
}
void GlzDecoderWindow::post_decode(GlzDecodedImage *image)
{
post_decode_intialize();
post_decode_update_window(image);
}
/* index: the physical index in the images array. Note that it can't change between waits since
the realloc mutex should be read locked.
No starvation for the realloc mutex can occur, since the image we wait for is located before us,
hence, when it arrives - no realloc is needed. */
void GlzDecoderWindow::wait_for_image(int index)
{
Lock lock(_new_image_mutex);
GlzDecodedImage *image = _images[index]; // can be performed without locking the _win_mutex,
// since it is called after pre and the rw mutex is // locked, hence, physical changes to the window are
// not allowed. In addition the reading of the image ptr
// is atomic, thus, even if the value changes we are
// not affected.
while (!image) {
if (_aborting) {
THROW("aborting");
}
_new_image_cond.wait(lock);
image = _images[index];
}
}
void GlzDecoderWindow::abort()
{
Lock lock1(_win_modifiers_mutex);
Lock lock2(_new_image_mutex);
_aborting = true;
_new_image_cond.notify_all();
_release_image_cond.notify_all();
_win_alloc_cond.notify_all();
}
void GlzDecoderWindow::clear()
{
Lock lock(_win_modifiers_mutex);
release_images();
init();
}
void GlzDecoderWindow::init()
{
_missing_list.clear();
// The window is never empty: the head is in the missing list or in the window.
// The first missing image is 0.
_missing_list.push_front(0);
_head_idx = 0;
_tail_image_id = 0;
_n_images = 1;
}
void GlzDecoderWindow::release_images()
{
for (int i = 0; i < _n_images; i++) {
int idx = (_head_idx + i) % _images_capacity;
if (_images[idx]) {
delete _images[idx];
_images[idx] = NULL;
}
}
}
inline bool GlzDecoderWindow::is_empty()
{
return (!_n_images);
}
inline bool GlzDecoderWindow::will_overflow(uint64_t image_id, uint64_t relative_head_id)
{
if (image_id <= _tail_image_id) {
return false;
}
if (!_missing_list.empty() && (_missing_list.front() < relative_head_id)) {
// two non overlapping windows
return true;
}
return false;
}
DecodedImageWinId GlzDecoderWindow::pre_decode_update_window(uint64_t image_id,
uint64_t relative_head_id)
{
Lock lock(_win_modifiers_mutex);
int realloc_size;
while (will_overflow(image_id, relative_head_id)) {
if (_aborting) {
THROW("aborting");
}
_release_image_cond.wait(lock);
}
// The following conditions prevent starvation in case thread (1) should realloc,
// thread (2) is during decode and waits for a previous image and
/// thread (3) should decode this the previous image and needs to enter pre decode although
// (1) is in there.
// We must give priority to older images in the window.
// The condition should be checked over again in case a later image entered the window
// and the realocation was already performed
while ((realloc_size = calc_realloc_size(image_id))) {
if (_aborting) {
THROW("aborting");
}
if (_win_alloc_rw_mutex.try_write_lock()) {
realloc(realloc_size);
_win_alloc_rw_mutex.write_unlock();
break;
} else {
_win_alloc_cond.wait(lock);
}
}
if (image_id > _tail_image_id) { // not in missing list
add_pre_decoded_image(image_id);
}
return calc_image_win_idx(image_id);
}
void GlzDecoderWindow::add_pre_decoded_image(uint64_t image_id)
{
GLZ_ASSERT(_debug_calls, image_id > _tail_image_id);
GLZ_ASSERT(_debug_calls, image_id - _tail_image_id + _n_images < _images_capacity);
for (uint64_t miss_id = _tail_image_id + 1; miss_id <= image_id; miss_id++) {
_missing_list.push_back(miss_id);
_n_images++;
}
_tail_image_id = image_id;
}
inline int GlzDecoderWindow::calc_realloc_size(uint64_t new_tail_image_id)
{
if (new_tail_image_id <= _tail_image_id) {
return 0;
}
int min_capacity = (int)(_n_images + new_tail_image_id - _tail_image_id);
if ((min_capacity * WIN_REALLOC_FACTOR) > _images_capacity) {
return (int)MAX(min_capacity * WIN_REALLOC_FACTOR, WIN_REALLOC_FACTOR * _images_capacity);
} else {
return 0;
}
}
void GlzDecoderWindow::realloc(int size)
{
GlzDecodedImage **new_images = new GlzDecodedImage*[size];
if (!new_images) {
_debug_calls.error(std::string("failed allocating images array"));
}
memset(new_images, 0, sizeof(GlzDecodedImage*) * size);
for (int i = 0; i < _n_images; i++) {
new_images[i] = _images[(i + _head_idx) % _images_capacity];
}
delete[] _images;
_images = new_images;
_head_idx = 0;
_images_capacity = size;
}
void GlzDecoderWindow::pre_decode_finalize()
{
_win_alloc_rw_mutex.read_lock();
}
void GlzDecoderWindow::post_decode_intialize()
{
_win_alloc_rw_mutex.read_unlock();
}
void GlzDecoderWindow::post_decode_update_window(GlzDecodedImage *image)
{
Lock lock(_win_modifiers_mutex);
add_decoded_image(image);
narrow_window(image);
_win_alloc_cond.notify_all();
}
void GlzDecoderWindow::add_decoded_image(GlzDecodedImage *image)
{
Lock lock(_new_image_mutex);
GLZ_ASSERT(_debug_calls, image->get_id() <= _tail_image_id);
_images[calc_image_win_idx(image->get_id())] = image;
_new_image_cond.notify_all();
}
/* Important observations:
1) When an image is added, if it is not the first missing image, it is not removed
immediately from the missing list (in order not to store another pointer to
the missing list inside the window ,or otherwise, to go over the missing list
and look for the image).
2) images that weren't removed from the missing list in their addition time, will be removed when
preliminary images will be added.
3) The first item in the missing list is always really missing.
4) The missing list is always ordered by image id (see add_pre_decoded_image)
*/
void GlzDecoderWindow::narrow_window(GlzDecodedImage *last_added)
{
uint64_t new_head_image_id;
GLZ_ASSERT(_debug_calls, !_missing_list.empty());
if (_missing_list.front() != last_added->get_id()) {
return;
}
_missing_list.pop_front(); // removing the last added image from the missing list
/* maintaining the missing list: removing front images that already arrived */
while (!_missing_list.empty()) {
int front_win_idx = calc_image_win_idx(_missing_list.front());
if (_images[front_win_idx] == NULL) { // still missing
break;
} else {
_missing_list.pop_front();
}
}
/* removing unnecessary image from the window's head*/
if (_missing_list.empty()) {
new_head_image_id = _images[
calc_image_win_idx(_tail_image_id)]->get_window_head_id();
} else {
// there must be at least one image in the window since narrow_window is called
// from post decode
GLZ_ASSERT(_debug_calls, _images[calc_image_win_idx(_missing_list.front() - 1)]);
new_head_image_id = _images[
calc_image_win_idx(_missing_list.front() - 1)]->get_window_head_id();
}
remove_head(new_head_image_id);
}
inline void GlzDecoderWindow::remove_head(uint64_t new_head_image_id)
{
GLZ_ASSERT(_debug_calls, _images[_head_idx]);
int n_images_remove = (int)(new_head_image_id - _images[_head_idx]->get_id());
if (!n_images_remove) {
return;
}
for (int i = 0; i < n_images_remove; i++) {
int index = (_head_idx + i) % _images_capacity;
delete _images[index];
_images[index] = NULL;
}
_n_images -= n_images_remove;
_head_idx = (_head_idx + n_images_remove) % _images_capacity;
_release_image_cond.notify_all();
}
/* NOTE: can only be used when the window is locked. (i.e, not inside get_ref_pixel) */
inline int GlzDecoderWindow::calc_image_win_idx(uint64_t image_id)
{
return (int)((_head_idx + _n_images - 1 - (_tail_image_id - image_id)) % _images_capacity);
}

View File

@ -1,122 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_GLZ_DECODER_WINDOW
#define _H_GLZ_DECODER_WINDOW
#include "glz_decoder_config.h"
#include "glz_decoded_image.h"
#include <list>
#include "read_write_mutex.h"
typedef int DecodedImageWinId;
/*
The class represents the lz window of images, which is shared among the glz decoders
*/
class GlzDecoderWindow {
public:
GlzDecoderWindow(GlzDecoderDebug &debug_calls);
virtual ~GlzDecoderWindow();
DecodedImageWinId pre_decode(uint64_t image_id, uint64_t relative_head_id);
void post_decode(GlzDecodedImage *image);
/* NOTE - get_ref_pixel should be called only after pre_decode was called and
before post decode was called */
uint8_t *get_ref_pixel(DecodedImageWinId decoded_image_win_id, int dist_from_ref_image,
int pixel_offset);
void abort();
/* NOTE - clear mustn't be called if the window is currently used by a decoder*/
void clear();
private:
void wait_for_image(int index);
void add_image(GlzDecodedImage *image);
uint8_t* get_pixel_after_image_entered(int image_index, int pixel_offset);
bool will_overflow(uint64_t image_id, uint64_t relative_head_id);
bool is_empty();
DecodedImageWinId pre_decode_update_window(uint64_t image_id, uint64_t relative_head_id);
void pre_decode_finalize();
void post_decode_intialize();
void post_decode_update_window(GlzDecodedImage *image);
void add_pre_decoded_image(uint64_t image_id);
void add_decoded_image(GlzDecodedImage *image);
void narrow_window(GlzDecodedImage *last_added);
void remove_head(uint64_t new_head_image_id);
int calc_image_win_idx(uint64_t image_id);
int calc_realloc_size(uint64_t new_tail_image_id);
void realloc(int size);
void init();
void release_images();
private:
GlzDecodedImage **_images; // cyclic window
int _head_idx; // index in images array (not image id)
uint64_t _tail_image_id;
int _images_capacity;
int _n_images; // _n_images counts all the images in
// the window, including the missing ones
std::list<uint64_t> _missing_list;
Mutex _win_modifiers_mutex;
ReadWriteMutex _win_alloc_rw_mutex;
Mutex _new_image_mutex;
Condition _new_image_cond; // when get_pixel_ref waits for an image
Condition _release_image_cond; // when waiting for the window to narrow.
Condition _win_alloc_cond;
bool _aborting;
GlzDecoderDebug &_debug_calls;
};
inline uint8_t* GlzDecoderWindow::get_pixel_after_image_entered(int image_index,
int pixel_offset)
{
return _images[image_index]->get_pixel_ref(pixel_offset);
}
/* should be called only between pre and post (when realloc mutex is write-locked).
Note that it can't use calc_image_win_idx, since the window is not locked for changes
(that are not reallocation) during decoding.*/
inline uint8_t *GlzDecoderWindow::get_ref_pixel(DecodedImageWinId decoded_image_win_id,
int dist_from_ref_image, int pixel_offset)
{
int ref_image_index = (dist_from_ref_image <= decoded_image_win_id) ?
(decoded_image_win_id - dist_from_ref_image) :
_images_capacity + (decoded_image_win_id - dist_from_ref_image);
if (_images[ref_image_index] == NULL) { // reading image is atomic
wait_for_image(ref_image_index);
}
// after image entered - it won't leave the window till no decoder needs it
return get_pixel_after_image_entered(ref_image_index, pixel_offset);
}
#endif // _H_GLZ_DECODER_WINDOW

View File

@ -1,20 +0,0 @@
NULL =
EXTRA_DIST = \
commonv2c.ttf.c \
commonwealth-10.font.c \
dejavu_sans-10.font.c \
dejavu_sans.ttf.c \
gui.cpp \
gui.h \
resource_provider.cpp \
resource_provider.h \
softrenderer.cpp \
softrenderer.h \
softtexture.cpp \
softtexture.h \
taharez_look.imageset.c \
taharez_look.looknfeel.c \
taharez_look.scheme.c \
taharez_look.tga.c \
$(NULL)

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
const unsigned char commonwealth_10_font[] = {
0x3c,0x3f,0x78,0x6d,0x6c,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,
0x2e,0x30,0x22,0x20,0x3f,0x3e,0x0a,0x3c,0x46,0x6f,0x6e,0x74,0x20,0x4e,0x61,0x6d,
0x65,0x3d,0x22,0x43,0x6f,0x6d,0x6d,0x6f,0x6e,0x77,0x65,0x61,0x6c,0x74,0x68,0x2d,
0x31,0x30,0x22,0x20,0x46,0x69,0x6c,0x65,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x43,0x6f,
0x6d,0x6d,0x6f,0x6e,0x76,0x32,0x63,0x2e,0x74,0x74,0x66,0x22,0x20,0x54,0x79,0x70,
0x65,0x3d,0x22,0x46,0x72,0x65,0x65,0x54,0x79,0x70,0x65,0x22,0x20,0x53,0x69,0x7a,
0x65,0x3d,0x22,0x31,0x30,0x22,0x20,0x4e,0x61,0x74,0x69,0x76,0x65,0x48,0x6f,0x72,
0x7a,0x52,0x65,0x73,0x3d,0x22,0x38,0x30,0x30,0x22,0x20,0x4e,0x61,0x74,0x69,0x76,
0x65,0x56,0x65,0x72,0x74,0x52,0x65,0x73,0x3d,0x22,0x36,0x30,0x30,0x22,0x20,0x41,
0x75,0x74,0x6f,0x53,0x63,0x61,0x6c,0x65,0x64,0x3d,0x22,0x74,0x72,0x75,0x65,0x22,
0x2f,0x3e,0x0a};

View File

@ -1,12 +0,0 @@
const unsigned char dejavu_sans_10_font[] = {
0x3c,0x3f,0x78,0x6d,0x6c,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,
0x2e,0x30,0x22,0x20,0x3f,0x3e,0x0a,0x3c,0x46,0x6f,0x6e,0x74,0x20,0x4e,0x61,0x6d,
0x65,0x3d,0x22,0x44,0x65,0x6a,0x61,0x56,0x75,0x53,0x61,0x6e,0x73,0x2d,0x31,0x30,
0x22,0x20,0x46,0x69,0x6c,0x65,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x44,0x65,0x6a,0x61,
0x56,0x75,0x53,0x61,0x6e,0x73,0x2e,0x74,0x74,0x66,0x22,0x20,0x54,0x79,0x70,0x65,
0x3d,0x22,0x46,0x72,0x65,0x65,0x54,0x79,0x70,0x65,0x22,0x20,0x53,0x69,0x7a,0x65,
0x3d,0x22,0x31,0x30,0x22,0x20,0x4e,0x61,0x74,0x69,0x76,0x65,0x48,0x6f,0x72,0x7a,
0x52,0x65,0x73,0x3d,0x22,0x38,0x30,0x30,0x22,0x20,0x4e,0x61,0x74,0x69,0x76,0x65,
0x56,0x65,0x72,0x74,0x52,0x65,0x73,0x3d,0x22,0x36,0x30,0x30,0x22,0x20,0x41,0x75,
0x74,0x6f,0x53,0x63,0x61,0x6c,0x65,0x64,0x3d,0x22,0x74,0x72,0x75,0x65,0x22,0x2f,
0x3e,0x0a};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,143 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_GUI
#define _H_GUI
#include "softrenderer.h"
#include "screen_layer.h"
#include "inputs_handler.h"
#include "application.h"
class RedPixmapSw;
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;}
#ifdef USE_GUI
CEGUI::System& gui_system() { return *_gui_system;}
#endif // USE_GUI
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,
WARNING,
ERROR_MSG
};
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);
void dettach_dialog(Dialog* dialog);
private:
Application& _app;
Application::State _state;
RedPixmapSw* _pixmap;
#ifdef USE_GUI
CEGUI::SoftRenderer* _renderer;
CEGUI::System* _gui_system;
#endif // USE_GUI
Dialog* _dialog;
uint64_t _prev_time;
TabFactorys _tab_factorys;
friend class Dialog;
};
class GUI::Tab {
public:
virtual ~Tab() {}
#ifdef USE_GUI
virtual CEGUI::Window& get_root_window() = 0;
#endif // USE_GUI
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

View File

@ -1,148 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#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, "Secure 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;
}

View File

@ -1,59 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RESOURCE_PROVIDER
#define _H_RESOURCE_PROVIDER
/* CEGUI 0.6 bug, CEGUITexture.h doesn't include this, we need to */
#include <cstddef>
#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

View File

@ -1,390 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "common.h"
#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;
}
}

View File

@ -1,148 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _directfbrenderer_h_
#define _directfbrenderer_h_
#include <stdint.h>
#include <list>
#include <set>
/* CEGUI 0.6 bug, CEGUITexture.h doesn't include this, we need to */
#include <cstddef>
#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

View File

@ -1,139 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "common.h"
#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");
}
}
}

View File

@ -1,58 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _softtexture_h_
#define _softtexture_h_
#include <stdint.h>
/* CEGUI 0.6 bug, CEGUITexture.h doesn't include this, we need to */
#include <cstddef>
#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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,449 +0,0 @@
const unsigned char taharez_look_schem[] = {
0x3c,0x3f,0x78,0x6d,0x6c,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,
0x2e,0x30,0x22,0x20,0x3f,0x3e,0x0a,0x3c,0x47,0x55,0x49,0x53,0x63,0x68,0x65,0x6d,
0x65,0x20,0x4e,0x61,0x6d,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,
0x6f,0x6f,0x6b,0x22,0x3e,0x0a,0x09,0x3c,0x49,0x6d,0x61,0x67,0x65,0x73,0x65,0x74,
0x20,0x4e,0x61,0x6d,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,
0x6f,0x6b,0x22,0x20,0x46,0x69,0x6c,0x65,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x54,0x61,
0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2e,0x69,0x6d,0x61,0x67,0x65,0x73,
0x65,0x74,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x6f,0x6e,0x74,0x20,0x4e,0x61,
0x6d,0x65,0x3d,0x22,0x43,0x6f,0x6d,0x6d,0x6f,0x6e,0x77,0x65,0x61,0x6c,0x74,0x68,
0x2d,0x31,0x30,0x22,0x20,0x46,0x69,0x6c,0x65,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x43,
0x6f,0x6d,0x6d,0x6f,0x6e,0x77,0x65,0x61,0x6c,0x74,0x68,0x2d,0x31,0x30,0x2e,0x66,
0x6f,0x6e,0x74,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,
0x65,0x65,0x6c,0x20,0x46,0x69,0x6c,0x65,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x54,0x61,
0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2e,0x6c,0x6f,0x6f,0x6b,0x6e,0x66,
0x65,0x65,0x6c,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x57,0x69,0x6e,0x64,0x6f,0x77,
0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x53,0x65,0x74,0x20,0x46,0x69,0x6c,0x65,
0x6e,0x61,0x6d,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x46,0x61,0x6c,0x61,0x67,
0x61,0x72,0x64,0x57,0x52,0x42,0x61,0x73,0x65,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,
0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,
0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,
0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,
0x20,0x20,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,
0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x50,0x75,0x73,0x68,0x42,0x75,0x74,0x74,0x6f,
0x6e,0x22,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,
0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,
0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x42,0x75,0x74,0x74,
0x6f,0x6e,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,
0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,
0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,
0x2f,0x43,0x68,0x65,0x63,0x6b,0x62,0x6f,0x78,0x22,0x20,0x20,0x20,0x20,0x54,0x61,
0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,
0x43,0x68,0x65,0x63,0x6b,0x62,0x6f,0x78,0x22,0x20,0x20,0x20,0x20,0x52,0x65,0x6e,
0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,
0x54,0x6f,0x67,0x67,0x6c,0x65,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x4c,0x6f,
0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,
0x4c,0x6f,0x6f,0x6b,0x2f,0x43,0x68,0x65,0x63,0x6b,0x62,0x6f,0x78,0x22,0x20,0x2f,
0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,
0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,
0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x49,0x6d,0x61,0x67,
0x65,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,
0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x50,0x75,0x73,0x68,0x42,
0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,
0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x42,0x75,0x74,0x74,0x6f,
0x6e,0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,
0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,
0x49,0x6d,0x61,0x67,0x65,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x2f,0x3e,0x0a,
0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,
0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,
0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x52,0x61,0x64,0x69,0x6f,0x42,
0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,
0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x52,0x61,0x64,0x69,0x6f,0x42,0x75,
0x74,0x74,0x6f,0x6e,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,
0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x54,0x6f,0x67,0x67,0x6c,0x65,0x42,
0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,
0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x52,0x61,
0x64,0x69,0x6f,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,
0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,
0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,
0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x46,0x72,0x61,0x6d,0x65,0x57,0x69,0x6e,
0x64,0x6f,0x77,0x22,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,
0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x46,0x72,0x61,0x6d,0x65,0x57,0x69,0x6e,
0x64,0x6f,0x77,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,
0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x46,0x72,0x61,0x6d,0x65,0x57,0x69,0x6e,
0x64,0x6f,0x77,0x22,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,
0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x46,0x72,0x61,
0x6d,0x65,0x57,0x69,0x6e,0x64,0x6f,0x77,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,
0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,
0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,
0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x69,0x74,0x6c,0x65,0x62,0x61,0x72,0x22,
0x20,0x20,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,
0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x54,0x69,0x74,0x6c,0x65,0x62,0x61,0x72,0x22,
0x20,0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,
0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x54,0x69,0x74,0x6c,0x65,0x62,0x61,0x72,0x22,
0x20,0x20,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,
0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x69,0x74,0x6c,
0x65,0x62,0x61,0x72,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,
0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,
0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,
0x6f,0x6b,0x2f,0x53,0x79,0x73,0x74,0x65,0x6d,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,
0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,
0x55,0x49,0x2f,0x50,0x75,0x73,0x68,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x20,
0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,
0x72,0x64,0x2f,0x53,0x79,0x73,0x74,0x65,0x6d,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,
0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,
0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,
0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,
0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,
0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x45,0x64,0x69,
0x74,0x62,0x6f,0x78,0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x54,
0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,
0x2f,0x45,0x64,0x69,0x74,0x62,0x6f,0x78,0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,
0x61,0x67,0x61,0x72,0x64,0x2f,0x45,0x64,0x69,0x74,0x62,0x6f,0x78,0x22,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,
0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x45,
0x64,0x69,0x74,0x62,0x6f,0x78,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,
0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,
0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,
0x4c,0x6f,0x6f,0x6b,0x2f,0x4d,0x75,0x6c,0x74,0x69,0x4c,0x69,0x6e,0x65,0x45,0x64,
0x69,0x74,0x62,0x6f,0x78,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,
0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x4d,0x75,0x6c,0x74,0x69,0x4c,0x69,
0x6e,0x65,0x45,0x64,0x69,0x74,0x62,0x6f,0x78,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,
0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x4d,0x75,
0x6c,0x74,0x69,0x4c,0x69,0x6e,0x65,0x45,0x64,0x69,0x74,0x62,0x6f,0x78,0x22,0x20,
0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,
0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4d,0x75,0x6c,0x74,0x69,0x4c,0x69,0x6e,0x65,
0x45,0x64,0x69,0x74,0x62,0x6f,0x78,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,
0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,
0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,
0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4d,0x65,0x6e,0x75,0x62,0x61,0x72,0x22,0x20,0x20,
0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,
0x55,0x49,0x2f,0x4d,0x65,0x6e,0x75,0x62,0x61,0x72,0x22,0x20,0x20,0x20,0x52,0x65,
0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,
0x2f,0x4d,0x65,0x6e,0x75,0x62,0x61,0x72,0x22,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,
0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,
0x6f,0x6b,0x2f,0x4d,0x65,0x6e,0x75,0x62,0x61,0x72,0x22,0x20,0x2f,0x3e,0x0a,0x09,
0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,
0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,
0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x50,0x6f,0x70,0x75,0x70,0x4d,0x65,
0x6e,0x75,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,
0x43,0x45,0x47,0x55,0x49,0x2f,0x50,0x6f,0x70,0x75,0x70,0x4d,0x65,0x6e,0x75,0x22,
0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,
0x61,0x72,0x64,0x2f,0x50,0x6f,0x70,0x75,0x70,0x4d,0x65,0x6e,0x75,0x22,0x20,0x4c,
0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,
0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x50,0x6f,0x70,0x75,0x70,0x4d,0x65,0x6e,0x75,0x22,
0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,
0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,
0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4d,0x65,
0x6e,0x75,0x49,0x74,0x65,0x6d,0x22,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,
0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x4d,0x65,0x6e,0x75,0x49,
0x74,0x65,0x6d,0x22,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,
0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x4d,0x65,0x6e,0x75,0x49,0x74,0x65,
0x6d,0x22,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,
0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4d,0x65,0x6e,0x75,0x49,
0x74,0x65,0x6d,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,
0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,
0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,
0x6b,0x2f,0x41,0x6c,0x74,0x65,0x72,0x6e,0x61,0x74,0x65,0x50,0x72,0x6f,0x67,0x72,
0x65,0x73,0x73,0x42,0x61,0x72,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,
0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x50,0x72,0x6f,0x67,0x72,0x65,
0x73,0x73,0x42,0x61,0x72,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,
0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x50,0x72,0x6f,0x67,0x72,0x65,
0x73,0x73,0x42,0x61,0x72,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,
0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x41,0x6c,
0x74,0x50,0x72,0x6f,0x67,0x72,0x65,0x73,0x73,0x42,0x61,0x72,0x22,0x20,0x2f,0x3e,
0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,
0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,
0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x50,0x72,0x6f,0x67,0x72,
0x65,0x73,0x73,0x42,0x61,0x72,0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,
0x55,0x49,0x2f,0x50,0x72,0x6f,0x67,0x72,0x65,0x73,0x73,0x42,0x61,0x72,0x22,0x20,
0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,
0x72,0x64,0x2f,0x50,0x72,0x6f,0x67,0x72,0x65,0x73,0x73,0x42,0x61,0x72,0x22,0x20,
0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,
0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x50,0x72,0x6f,0x67,0x72,0x65,0x73,0x73,0x42,
0x61,0x72,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,
0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,
0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,
0x2f,0x56,0x55,0x4d,0x65,0x74,0x65,0x72,0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,
0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x50,0x72,0x6f,0x67,0x72,0x65,0x73,
0x73,0x42,0x61,0x72,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,
0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x50,0x72,0x6f,0x67,0x72,0x65,0x73,
0x73,0x42,0x61,0x72,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,
0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x56,0x55,0x4d,
0x65,0x74,0x65,0x72,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,
0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,
0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,
0x6f,0x6b,0x2f,0x56,0x65,0x72,0x74,0x69,0x63,0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,
0x6c,0x62,0x61,0x72,0x22,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,
0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x53,0x63,0x72,0x6f,0x6c,0x6c,
0x62,0x61,0x72,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,
0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,
0x72,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,
0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x56,0x65,0x72,0x74,0x69,0x63,
0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,0x72,0x22,0x20,0x2f,0x3e,0x0a,
0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,
0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,
0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x48,0x6f,0x72,0x69,0x7a,0x6f,
0x6e,0x74,0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,0x72,0x22,0x20,0x54,
0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,
0x2f,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,0x72,0x22,0x20,0x52,0x65,0x6e,0x64,
0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x53,
0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,0x72,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,
0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,
0x2f,0x48,0x6f,0x72,0x69,0x7a,0x6f,0x6e,0x74,0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,
0x6c,0x62,0x61,0x72,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,
0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,
0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,
0x6f,0x6b,0x2f,0x56,0x65,0x72,0x74,0x69,0x63,0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,
0x6c,0x62,0x61,0x72,0x54,0x68,0x75,0x6d,0x62,0x22,0x20,0x20,0x20,0x54,0x61,0x72,
0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x54,
0x68,0x75,0x6d,0x62,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,
0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,
0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,
0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x56,0x65,0x72,0x74,0x69,0x63,0x61,0x6c,
0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,0x72,0x54,0x68,0x75,0x6d,0x62,0x22,0x20,
0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,
0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,
0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x48,0x6f,0x72,
0x69,0x7a,0x6f,0x6e,0x74,0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,0x72,
0x54,0x68,0x75,0x6d,0x62,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,
0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x54,0x68,0x75,0x6d,0x62,0x22,0x20,
0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,
0x72,0x64,0x2f,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,
0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,
0x6b,0x2f,0x48,0x6f,0x72,0x69,0x7a,0x6f,0x6e,0x74,0x61,0x6c,0x53,0x63,0x72,0x6f,
0x6c,0x6c,0x62,0x61,0x72,0x54,0x68,0x75,0x6d,0x62,0x22,0x20,0x2f,0x3e,0x0a,0x09,
0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,
0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,
0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4c,0x61,0x72,0x67,0x65,0x56,0x65,
0x72,0x74,0x69,0x63,0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,0x72,0x22,
0x20,0x20,0x20,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,
0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,
0x72,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,
0x61,0x67,0x61,0x72,0x64,0x2f,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,0x72,0x22,
0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,
0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4c,0x61,0x72,0x67,0x65,0x56,0x65,0x72,
0x74,0x69,0x63,0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,0x61,0x72,0x22,0x20,
0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,
0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,
0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4c,0x61,0x72,
0x67,0x65,0x56,0x65,0x72,0x74,0x69,0x63,0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,0x6c,
0x62,0x61,0x72,0x54,0x68,0x75,0x6d,0x62,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,
0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x54,0x68,0x75,0x6d,
0x62,0x22,0x20,0x20,0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,
0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x42,0x75,0x74,0x74,0x6f,0x6e,
0x22,0x20,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,
0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4c,0x61,0x72,0x67,
0x65,0x56,0x65,0x72,0x74,0x69,0x63,0x61,0x6c,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x62,
0x61,0x72,0x54,0x68,0x75,0x6d,0x62,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,
0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,
0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,
0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x61,0x62,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,
0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,
0x47,0x55,0x49,0x2f,0x54,0x61,0x62,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x20,
0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,
0x72,0x64,0x2f,0x54,0x61,0x62,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x20,0x4c,
0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,
0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x61,0x62,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,
0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,
0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,
0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x61,
0x62,0x43,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,
0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x54,0x61,0x62,0x43,
0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,
0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x54,0x61,0x62,0x43,0x6f,
0x6e,0x74,0x72,0x6f,0x6c,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,
0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x61,
0x62,0x43,0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,
0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,
0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,
0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x61,0x62,0x43,0x6f,0x6e,0x74,0x65,0x6e,
0x74,0x50,0x61,0x6e,0x65,0x22,0x20,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,
0x54,0x79,0x70,0x65,0x3d,0x22,0x44,0x65,0x66,0x61,0x75,0x6c,0x74,0x57,0x69,0x6e,
0x64,0x6f,0x77,0x22,0x20,0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,
0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x44,0x65,0x66,0x61,0x75,
0x6c,0x74,0x22,0x20,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,
0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x61,
0x62,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x50,0x61,0x6e,0x65,0x22,0x20,0x2f,0x3e,
0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,
0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,
0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x61,0x62,0x42,0x75,
0x74,0x74,0x6f,0x6e,0x50,0x61,0x6e,0x65,0x22,0x20,0x20,0x20,0x20,0x54,0x61,0x72,
0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x44,0x65,0x66,0x61,0x75,0x6c,0x74,
0x57,0x69,0x6e,0x64,0x6f,0x77,0x22,0x20,0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,
0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x44,0x65,
0x66,0x61,0x75,0x6c,0x74,0x22,0x20,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,
0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,
0x2f,0x54,0x61,0x62,0x42,0x75,0x74,0x74,0x6f,0x6e,0x50,0x61,0x6e,0x65,0x22,0x20,
0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,
0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,
0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x43,0x6f,0x6d,
0x62,0x6f,0x44,0x72,0x6f,0x70,0x4c,0x69,0x73,0x74,0x22,0x20,0x54,0x61,0x72,0x67,
0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x43,0x6f,
0x6d,0x62,0x6f,0x44,0x72,0x6f,0x70,0x4c,0x69,0x73,0x74,0x22,0x20,0x52,0x65,0x6e,
0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,
0x4c,0x69,0x73,0x74,0x62,0x6f,0x78,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,
0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,
0x43,0x6f,0x6d,0x62,0x6f,0x44,0x72,0x6f,0x70,0x4c,0x69,0x73,0x74,0x22,0x20,0x2f,
0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,
0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,
0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x43,0x6f,0x6d,0x62,
0x6f,0x45,0x64,0x69,0x74,0x62,0x6f,0x78,0x22,0x20,0x20,0x54,0x61,0x72,0x67,0x65,
0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x45,0x64,0x69,
0x74,0x62,0x6f,0x78,0x22,0x09,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,
0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x45,0x64,0x69,0x74,0x62,0x6f,
0x78,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,
0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x43,0x6f,0x6d,0x62,0x6f,0x45,
0x64,0x69,0x74,0x62,0x6f,0x78,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,
0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,
0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,
0x4c,0x6f,0x6f,0x6b,0x2f,0x43,0x6f,0x6d,0x62,0x6f,0x62,0x6f,0x78,0x22,0x09,0x54,
0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,
0x2f,0x43,0x6f,0x6d,0x62,0x6f,0x62,0x6f,0x78,0x22,0x09,0x20,0x52,0x65,0x6e,0x64,
0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x44,
0x65,0x66,0x61,0x75,0x6c,0x74,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,
0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x43,
0x6f,0x6d,0x62,0x6f,0x62,0x6f,0x78,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,
0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,
0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,
0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4c,0x69,0x73,0x74,0x62,0x6f,0x78,0x22,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,
0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x4c,0x69,0x73,0x74,0x62,
0x6f,0x78,0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x52,0x65,
0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,
0x2f,0x4c,0x69,0x73,0x74,0x62,0x6f,0x78,0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,
0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4c,0x69,0x73,0x74,0x62,
0x6f,0x78,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,
0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,
0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,
0x2f,0x4c,0x69,0x73,0x74,0x48,0x65,0x61,0x64,0x65,0x72,0x22,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,
0x43,0x45,0x47,0x55,0x49,0x2f,0x4c,0x69,0x73,0x74,0x48,0x65,0x61,0x64,0x65,0x72,
0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,
0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x4c,0x69,0x73,0x74,
0x48,0x65,0x61,0x64,0x65,0x72,0x22,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x4c,
0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,
0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4c,0x69,0x73,0x74,0x48,0x65,0x61,0x64,0x65,0x72,
0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,
0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,
0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4c,
0x69,0x73,0x74,0x48,0x65,0x61,0x64,0x65,0x72,0x53,0x65,0x67,0x6d,0x65,0x6e,0x74,
0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,
0x47,0x55,0x49,0x2f,0x4c,0x69,0x73,0x74,0x48,0x65,0x61,0x64,0x65,0x72,0x53,0x65,
0x67,0x6d,0x65,0x6e,0x74,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,
0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x4c,0x69,0x73,0x74,0x48,0x65,
0x61,0x64,0x65,0x72,0x53,0x65,0x67,0x6d,0x65,0x6e,0x74,0x22,0x20,0x4c,0x6f,0x6f,
0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,
0x6f,0x6f,0x6b,0x2f,0x4c,0x69,0x73,0x74,0x48,0x65,0x61,0x64,0x65,0x72,0x53,0x65,
0x67,0x6d,0x65,0x6e,0x74,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,
0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,
0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,
0x6f,0x6f,0x6b,0x2f,0x4d,0x75,0x6c,0x74,0x69,0x43,0x6f,0x6c,0x75,0x6d,0x6e,0x4c,
0x69,0x73,0x74,0x22,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,
0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x4d,0x75,0x6c,0x74,0x69,0x43,0x6f,
0x6c,0x75,0x6d,0x6e,0x4c,0x69,0x73,0x74,0x22,0x20,0x20,0x20,0x52,0x65,0x6e,0x64,
0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x4d,
0x75,0x6c,0x74,0x69,0x43,0x6f,0x6c,0x75,0x6d,0x6e,0x4c,0x69,0x73,0x74,0x22,0x20,
0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,
0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4d,0x75,0x6c,0x74,0x69,0x43,0x6f,
0x6c,0x75,0x6d,0x6e,0x4c,0x69,0x73,0x74,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,
0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,
0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,
0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x53,0x6c,0x69,0x64,0x65,0x72,0x22,0x20,0x20,
0x20,0x20,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,
0x43,0x45,0x47,0x55,0x49,0x2f,0x53,0x6c,0x69,0x64,0x65,0x72,0x22,0x20,0x20,0x20,
0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,
0x61,0x67,0x61,0x72,0x64,0x2f,0x53,0x6c,0x69,0x64,0x65,0x72,0x22,0x20,0x20,0x4c,
0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,
0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x53,0x6c,0x69,0x64,0x65,0x72,0x22,0x20,0x2f,0x3e,
0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,
0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,
0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x53,0x6c,0x69,0x64,0x65,
0x72,0x54,0x68,0x75,0x6d,0x62,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,
0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x54,0x68,0x75,0x6d,0x62,0x22,
0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,
0x61,0x72,0x64,0x2f,0x42,0x75,0x74,0x74,0x6f,0x6e,0x22,0x20,0x20,0x4c,0x6f,0x6f,
0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,
0x6f,0x6f,0x6b,0x2f,0x53,0x6c,0x69,0x64,0x65,0x72,0x54,0x68,0x75,0x6d,0x62,0x22,
0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,
0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,
0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x53,0x63,
0x72,0x6f,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x50,0x61,0x6e,0x65,0x22,0x20,0x54,0x61,
0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,
0x53,0x63,0x72,0x6f,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x50,0x61,0x6e,0x65,0x22,0x20,
0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,
0x72,0x64,0x2f,0x53,0x63,0x72,0x6f,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x50,0x61,0x6e,
0x65,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,
0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x53,0x63,0x72,0x6f,0x6c,0x6c,
0x61,0x62,0x6c,0x65,0x50,0x61,0x6e,0x65,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,
0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,
0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,
0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x53,0x70,0x69,0x6e,0x6e,0x65,0x72,0x22,0x20,
0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,
0x49,0x2f,0x53,0x70,0x69,0x6e,0x6e,0x65,0x72,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,
0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x44,0x65,
0x66,0x61,0x75,0x6c,0x74,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,
0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x53,0x70,
0x69,0x6e,0x6e,0x65,0x72,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,
0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,
0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,
0x6f,0x6f,0x6b,0x2f,0x54,0x6f,0x6f,0x6c,0x74,0x69,0x70,0x22,0x20,0x54,0x61,0x72,
0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x54,
0x6f,0x6f,0x6c,0x74,0x69,0x70,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,
0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x54,0x6f,0x6f,0x6c,0x74,
0x69,0x70,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,
0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x6f,0x6f,0x6c,0x74,
0x69,0x70,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,
0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,
0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,
0x2f,0x53,0x74,0x61,0x74,0x69,0x63,0x49,0x6d,0x61,0x67,0x65,0x22,0x20,0x54,0x61,
0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x44,0x65,0x66,0x61,0x75,0x6c,
0x74,0x57,0x69,0x6e,0x64,0x6f,0x77,0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,
0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x53,0x74,0x61,0x74,
0x69,0x63,0x49,0x6d,0x61,0x67,0x65,0x22,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,
0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,
0x53,0x74,0x61,0x74,0x69,0x63,0x49,0x6d,0x61,0x67,0x65,0x22,0x20,0x2f,0x3e,0x0a,
0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,
0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,
0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x53,0x74,0x61,0x74,0x69,0x63,
0x54,0x65,0x78,0x74,0x22,0x20,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,
0x65,0x3d,0x22,0x44,0x65,0x66,0x61,0x75,0x6c,0x74,0x57,0x69,0x6e,0x64,0x6f,0x77,
0x22,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,
0x67,0x61,0x72,0x64,0x2f,0x53,0x74,0x61,0x74,0x69,0x63,0x54,0x65,0x78,0x74,0x22,
0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,
0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x53,0x74,0x61,0x74,0x69,0x63,0x54,
0x65,0x78,0x74,0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,
0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,
0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,
0x6b,0x2f,0x49,0x74,0x65,0x6d,0x4c,0x69,0x73,0x74,0x62,0x6f,0x78,0x22,0x20,0x54,
0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,
0x2f,0x49,0x74,0x65,0x6d,0x4c,0x69,0x73,0x74,0x62,0x6f,0x78,0x22,0x20,0x52,0x65,
0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,
0x2f,0x49,0x74,0x65,0x6d,0x4c,0x69,0x73,0x74,0x62,0x6f,0x78,0x22,0x20,0x4c,0x6f,
0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,
0x4c,0x6f,0x6f,0x6b,0x2f,0x49,0x74,0x65,0x6d,0x4c,0x69,0x73,0x74,0x62,0x6f,0x78,
0x22,0x20,0x2f,0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,
0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,
0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x4c,
0x69,0x73,0x74,0x62,0x6f,0x78,0x49,0x74,0x65,0x6d,0x22,0x20,0x54,0x61,0x72,0x67,
0x65,0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x49,0x74,
0x65,0x6d,0x45,0x6e,0x74,0x72,0x79,0x22,0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,
0x72,0x65,0x72,0x3d,0x22,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x49,0x74,
0x65,0x6d,0x45,0x6e,0x74,0x72,0x79,0x22,0x20,0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,
0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,
0x6b,0x2f,0x4c,0x69,0x73,0x74,0x62,0x6f,0x78,0x49,0x74,0x65,0x6d,0x22,0x20,0x2f,
0x3e,0x0a,0x09,0x3c,0x46,0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,
0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,
0x54,0x61,0x68,0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x47,0x72,0x6f,0x75,
0x70,0x42,0x6f,0x78,0x22,0x20,0x54,0x61,0x72,0x67,0x65,0x74,0x54,0x79,0x70,0x65,
0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x47,0x72,0x6f,0x75,0x70,0x42,0x6f,0x78,
0x22,0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,0x61,
0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x44,0x65,0x66,0x61,0x75,0x6c,0x74,0x22,0x20,
0x20,0x20,0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,
0x61,0x72,0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x47,0x72,0x6f,0x75,0x70,0x42,0x6f,
0x78,0x22,0x20,0x2f,0x3e,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x46,0x61,0x6c,
0x61,0x67,0x61,0x72,0x64,0x4d,0x61,0x70,0x70,0x69,0x6e,0x67,0x20,0x57,0x69,0x6e,
0x64,0x6f,0x77,0x54,0x79,0x70,0x65,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,0x65,0x7a,
0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x72,0x65,0x65,0x22,0x20,0x54,0x61,0x72,0x67,0x65,
0x74,0x54,0x79,0x70,0x65,0x3d,0x22,0x43,0x45,0x47,0x55,0x49,0x2f,0x54,0x72,0x65,
0x65,0x22,0x20,0x20,0x20,0x52,0x65,0x6e,0x64,0x65,0x72,0x65,0x72,0x3d,0x22,0x46,
0x61,0x6c,0x61,0x67,0x61,0x72,0x64,0x2f,0x54,0x72,0x65,0x65,0x22,0x20,0x20,0x20,
0x4c,0x6f,0x6f,0x6b,0x4e,0x46,0x65,0x65,0x6c,0x3d,0x22,0x54,0x61,0x68,0x61,0x72,
0x65,0x7a,0x4c,0x6f,0x6f,0x6b,0x2f,0x54,0x72,0x65,0x65,0x22,0x20,0x2f,0x3e,0x0a,
0x3c,0x2f,0x47,0x55,0x49,0x53,0x63,0x68,0x65,0x6d,0x65,0x3e,0x0a};

File diff suppressed because it is too large Load Diff

View File

@ -1,147 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "hot_keys.h"
#include "utils.h"
#include "debug.h"
HotKeysParser::HotKeysParser(const std::string& hotkeys, const CommandsMap& commands_map)
{
DBG(0, "hotkeys = %s", hotkeys.c_str());
std::istringstream is(hotkeys);
std::string hotkey;
while (std::getline(is, hotkey, ',')) {
add_hotkey(hotkey, commands_map);
}
}
void HotKeysParser::parse_keys(int command_id, const std::string& hotkey)
{
HotkeySet& keys = _hot_keys[command_id];
std::istringstream is(hotkey);
std::string key;
while (std::getline(is, key, '+')) {
add_key(keys, key.c_str());
}
}
void HotKeysParser::add_key(HotkeySet& keys, const char* key)
{
ASSERT(key != NULL);
static const struct {
const char* name;
RedKey main;
RedKey alter;
} keyboard[] = {
{ "alt", REDKEY_R_ALT, REDKEY_L_ALT },
{ "ralt", REDKEY_R_ALT, REDKEY_INVALID },
{ "rightalt", REDKEY_R_ALT, REDKEY_INVALID },
{ "right-alt", REDKEY_R_ALT, REDKEY_INVALID },
{ "lalt", REDKEY_L_ALT, REDKEY_INVALID },
{ "leftalt", REDKEY_L_ALT, REDKEY_INVALID },
{ "left-alt", REDKEY_L_ALT, REDKEY_INVALID },
{ "ctrl", REDKEY_R_CTRL, REDKEY_L_CTRL },
{ "rctrl", REDKEY_R_CTRL, REDKEY_INVALID },
{ "rightctrl", REDKEY_R_CTRL, REDKEY_INVALID },
{ "right-ctrl", REDKEY_R_CTRL, REDKEY_INVALID },
{ "lctrl", REDKEY_L_CTRL, REDKEY_INVALID },
{ "leftctrl", REDKEY_L_CTRL, REDKEY_INVALID },
{ "left-ctrl", REDKEY_L_CTRL, REDKEY_INVALID },
{ "shift", REDKEY_R_SHIFT, REDKEY_L_SHIFT },
{ "rshift", REDKEY_R_SHIFT, REDKEY_INVALID },
{ "rightshift", REDKEY_R_SHIFT, REDKEY_INVALID },
{ "right-shift", REDKEY_R_SHIFT, REDKEY_INVALID },
{ "lshift", REDKEY_L_SHIFT, REDKEY_INVALID },
{ "leftshift", REDKEY_L_SHIFT, REDKEY_INVALID },
{ "left-shift", REDKEY_L_SHIFT, REDKEY_INVALID },
{ "cmd", REDKEY_RIGHT_CMD, REDKEY_LEFT_CMD },
{ "rcmd", REDKEY_RIGHT_CMD, REDKEY_INVALID },
{ "rightcmd", REDKEY_RIGHT_CMD, REDKEY_INVALID },
{ "right-cmd", REDKEY_RIGHT_CMD, REDKEY_INVALID },
{ "lcmd", REDKEY_LEFT_CMD, REDKEY_INVALID },
{ "leftcmd", REDKEY_LEFT_CMD, REDKEY_INVALID },
{ "left-cmd", REDKEY_LEFT_CMD, REDKEY_INVALID },
{ "win", REDKEY_RIGHT_CMD, REDKEY_LEFT_CMD },
{ "rwin", REDKEY_RIGHT_CMD, REDKEY_INVALID },
{ "rightwin", REDKEY_RIGHT_CMD, REDKEY_INVALID },
{ "right-win", REDKEY_RIGHT_CMD, REDKEY_INVALID },
{ "lwin", REDKEY_LEFT_CMD, REDKEY_INVALID },
{ "leftwin", REDKEY_LEFT_CMD, REDKEY_INVALID },
{ "left-win", REDKEY_LEFT_CMD, REDKEY_INVALID },
{ "esc", REDKEY_ESCAPE, REDKEY_INVALID },
{ "escape", REDKEY_ESCAPE, REDKEY_INVALID },
{ "ins", REDKEY_INSERT, REDKEY_INVALID },
{ "insert", REDKEY_INSERT, REDKEY_INVALID },
{ "del", REDKEY_DELETE, REDKEY_INVALID },
{ "delete", REDKEY_DELETE, REDKEY_INVALID },
{ "pgup", REDKEY_PAGEUP, REDKEY_INVALID },
{ "pageup", REDKEY_PAGEUP, REDKEY_INVALID },
{ "pgdn", REDKEY_PAGEDOWN, REDKEY_INVALID },
{ "pagedown", REDKEY_PAGEDOWN, REDKEY_INVALID },
{ "home", REDKEY_HOME, REDKEY_INVALID },
{ "end", REDKEY_END, REDKEY_INVALID },
{ "space", REDKEY_SPACE, REDKEY_INVALID },
{ "enter", REDKEY_ENTER, REDKEY_INVALID },
{ "tab", REDKEY_TAB, REDKEY_INVALID },
{ "f1", REDKEY_F1, REDKEY_INVALID },
{ "f2", REDKEY_F2, REDKEY_INVALID },
{ "f3", REDKEY_F3, REDKEY_INVALID },
{ "f4", REDKEY_F4, REDKEY_INVALID },
{ "f5", REDKEY_F5, REDKEY_INVALID },
{ "f6", REDKEY_F6, REDKEY_INVALID },
{ "f7", REDKEY_F7, REDKEY_INVALID },
{ "f8", REDKEY_F8, REDKEY_INVALID },
{ "f9", REDKEY_F9, REDKEY_INVALID },
{ "f10", REDKEY_F10, REDKEY_INVALID },
{ "f11", REDKEY_F11, REDKEY_INVALID },
{ "f12", REDKEY_F12, REDKEY_INVALID }
};
for (unsigned i = 0; i < (sizeof(keyboard) / sizeof(keyboard[0])); ++i) {
if (strcasecmp(key, keyboard[i].name) == 0) {
HotkeyKey hotkey;
hotkey.main = keyboard[i].main;
hotkey.alter = keyboard[i].alter;
DBG(0, "keys = %s", keyboard[i].name);
keys.push_back(hotkey);
return;
}
}
THROW("unknown key name %s", key);
}
void HotKeysParser::add_hotkey(const std::string& hotkey, const CommandsMap& commands_map)
{
std::string::size_type key_start = hotkey.find('=', 0);
if (key_start == std::string::npos) {
THROW("unable to parse hot keys");
}
std::string command_name = hotkey.substr(0, key_start);
if (commands_map.find(command_name) == commands_map.end()) {
THROW("invalid action bname %s", command_name.c_str());
}
int command_id = commands_map.find(command_name)->second;
std::string keys = hotkey.substr(key_start + 1);
parse_keys(command_id, keys);
}

View File

@ -1,48 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_HOT_KEYS
#define _H_HOT_KEYS
#include "common.h"
#include "red_key.h"
typedef std::map<std::string, int> CommandsMap;
struct HotkeyKey {
RedKey main;
RedKey alter;
};
typedef std::vector<HotkeyKey> HotkeySet;
typedef std::map<int, HotkeySet> HotKeys;
class HotKeysParser {
public:
HotKeysParser(const std::string& hotkeys, const CommandsMap& commands_map);
const HotKeys& get() { return _hot_keys;}
private:
void add_hotkey(const std::string& hotkey, const CommandsMap& commands_map);
void parse_keys(int command_id, const std::string& hotkey);
void add_key(HotkeySet& keys, const char* key);
private:
HotKeys _hot_keys;
};
#endif

View File

@ -1,35 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_ICON
#define _H_ICON
class Icon {
public:
Icon() : _refs (1) {}
Icon* ref() { _refs++; return this;}
void unref() { if (!--_refs) delete this;}
protected:
virtual ~Icon() {}
private:
int _refs;
};
#endif

View File

@ -1,614 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "inputs_channel.h"
#include "utils.h"
#include "debug.h"
#include "red_client.h"
#include "application.h"
#include "display_channel.h"
#define SYNC_REMOTE_MODIFIERS
class SetInputsHandlerEvent: public Event {
public:
SetInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {}
class AttachFunc: public ForEachChannelFunc {
public:
AttachFunc(InputsChannel& channel)
: _channel (channel)
{
}
virtual bool operator() (RedChannel& channel)
{
if (channel.get_type() == SPICE_CHANNEL_DISPLAY) {
static_cast<DisplayChannel&>(channel).attach_inputs(&_channel);
}
return true;
}
public:
InputsChannel& _channel;
};
virtual void response(AbstractProcessLoop& events_loop)
{
static_cast<Application*>(events_loop.get_owner())->set_key_handler(_channel);
static_cast<Application*>(events_loop.get_owner())->set_mouse_handler(_channel);
AttachFunc func(_channel);
_channel.get_client().for_each_channel(func);
}
private:
InputsChannel& _channel;
};
class KeyModifiersEvent: public Event {
public:
KeyModifiersEvent(InputsChannel& channel) : _channel (channel) {}
virtual void response(AbstractProcessLoop& events_loop)
{
Lock lock(_channel._update_modifiers_lock);
_channel._active_modifiers_event = false;
_channel.set_local_modifiers();
}
private:
InputsChannel& _channel;
};
class RemoveInputsHandlerEvent: public SyncEvent {
public:
RemoveInputsHandlerEvent(InputsChannel& channel) : _channel (channel) {}
class DetachFunc: public ForEachChannelFunc {
public:
virtual bool operator() (RedChannel& channel)
{
if (channel.get_type() == SPICE_CHANNEL_DISPLAY) {
static_cast<DisplayChannel&>(channel).detach_inputs();
}
return true;
}
};
virtual void do_response(AbstractProcessLoop& events_loop)
{
static_cast<Application*>(events_loop.get_owner())->remove_key_handler(_channel);
static_cast<Application*>(events_loop.get_owner())->remove_mouse_handler(_channel);
DetachFunc detach_func;
_channel.get_client().for_each_channel(detach_func);
}
private:
InputsChannel& _channel;
};
class MotionMessage: public RedChannel::OutMessage, public RedPeer::OutMessage {
public:
MotionMessage(InputsChannel& channel);
virtual RedPeer::OutMessage& peer_message();
virtual void release();
private:
InputsChannel& _channel;
};
MotionMessage::MotionMessage(InputsChannel& channel)
: RedChannel::OutMessage()
, RedPeer::OutMessage(SPICE_MSGC_INPUTS_MOUSE_MOTION)
, _channel (channel)
{
}
void MotionMessage::release()
{
delete this;
}
RedPeer::OutMessage& MotionMessage::peer_message()
{
_channel.marshall_motion_event(_marshaller);
return *this;
}
class PositionMessage: public RedChannel::OutMessage, public RedPeer::OutMessage {
public:
PositionMessage(InputsChannel& channel);
virtual RedPeer::OutMessage& peer_message();
virtual void release();
private:
InputsChannel& _channel;
};
PositionMessage::PositionMessage(InputsChannel& channel)
: RedChannel::OutMessage()
, RedPeer::OutMessage(SPICE_MSGC_INPUTS_MOUSE_POSITION)
, _channel (channel)
{
}
void PositionMessage::release()
{
delete this;
}
RedPeer::OutMessage& PositionMessage::peer_message()
{
_channel.marshall_position_event(_marshaller);
return *this;
}
class InputsMessHandler: public MessageHandlerImp<InputsChannel, SPICE_CHANNEL_INPUTS> {
public:
InputsMessHandler(InputsChannel& channel)
: MessageHandlerImp<InputsChannel, SPICE_CHANNEL_INPUTS>(channel) {}
};
InputsChannel::InputsChannel(RedClient& client, uint32_t id)
: RedChannel(client, SPICE_CHANNEL_INPUTS, id, new InputsMessHandler(*this))
, _mouse_buttons_state (0)
, _mouse_dx (0)
, _mouse_dy (0)
, _mouse_x (~0)
, _mouse_y (~0)
, _display_id (-1)
, _active_motion (false)
, _motion_count (0)
, _active_modifiers_event (false)
{
InputsMessHandler* handler = static_cast<InputsMessHandler*>(get_message_handler());
handler->set_handler(SPICE_MSG_MIGRATE, &InputsChannel::handle_migrate);
handler->set_handler(SPICE_MSG_SET_ACK, &InputsChannel::handle_set_ack);
handler->set_handler(SPICE_MSG_PING, &InputsChannel::handle_ping);
handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &InputsChannel::handle_wait_for_channels);
handler->set_handler(SPICE_MSG_DISCONNECTING, &InputsChannel::handle_disconnect);
handler->set_handler(SPICE_MSG_NOTIFY, &InputsChannel::handle_notify);
handler->set_handler(SPICE_MSG_INPUTS_INIT, &InputsChannel::handle_init);
handler->set_handler(SPICE_MSG_INPUTS_KEY_MODIFIERS, &InputsChannel::handle_modifiers);
handler->set_handler(SPICE_MSG_INPUTS_MOUSE_MOTION_ACK, &InputsChannel::handle_motion_ack);
}
InputsChannel::~InputsChannel()
{
}
void InputsChannel::on_connect()
{
_motion_count = _mouse_dx = _mouse_dy = _mouse_buttons_state = _modifiers = 0;
_mouse_x = _mouse_y = ~0;
_display_id = -1;
}
void InputsChannel::on_disconnect()
{
AutoRef<RemoveInputsHandlerEvent> remove_handler_event(new RemoveInputsHandlerEvent(*this));
get_client().push_event(*remove_handler_event);
(*remove_handler_event)->wait();
}
void InputsChannel::handle_init(RedPeer::InMessage* message)
{
SpiceMsgInputsInit* init = (SpiceMsgInputsInit*)message->data();
_modifiers = init->keyboard_modifiers;
AutoRef<SetInputsHandlerEvent> set_handler_event(new SetInputsHandlerEvent(*this));
get_client().push_event(*set_handler_event);
}
void InputsChannel::handle_modifiers(RedPeer::InMessage* message)
{
SpiceMsgInputsKeyModifiers* init = (SpiceMsgInputsKeyModifiers*)message->data();
_modifiers = init->modifiers;
Lock lock(_update_modifiers_lock);
if (_active_modifiers_event) {
return;
}
_active_modifiers_event = true;
AutoRef<KeyModifiersEvent> modifiers_event(new KeyModifiersEvent(*this));
get_client().push_event(*modifiers_event);
}
void InputsChannel::handle_motion_ack(RedPeer::InMessage* message)
{
Lock lock(_motion_lock);
if (_motion_count < SPICE_INPUT_MOTION_ACK_BUNCH) {
LOG_WARN("invalid motion count");
_motion_count = 0;
} else {
_motion_count -= SPICE_INPUT_MOTION_ACK_BUNCH;
}
if (!_active_motion && (_mouse_dx || _mouse_dy || _display_id != -1)) {
_active_motion = true;
_motion_count++;
switch (get_client().get_mouse_mode()) {
case SPICE_MOUSE_MODE_CLIENT:
post_message(new PositionMessage(*this));
break;
case SPICE_MOUSE_MODE_SERVER:
post_message(new MotionMessage(*this));
break;
default:
THROW("invalid mouse mode");
}
}
}
void InputsChannel::marshall_motion_event(SpiceMarshaller *marshaller)
{
SpiceMsgcMouseMotion motion;
Lock lock(_motion_lock);
motion.buttons_state = _mouse_buttons_state;
motion.dx = _mouse_dx;
motion.dy = _mouse_dy;
_mouse_dx = _mouse_dy = 0;
_active_motion = false;
_marshallers->msgc_inputs_mouse_motion(marshaller, &motion);
}
void InputsChannel::marshall_position_event(SpiceMarshaller *marshaller)
{
SpiceMsgcMousePosition position;
Lock lock(_motion_lock);
position.buttons_state = _mouse_buttons_state;
position.x = _mouse_x;
position.y = _mouse_y;
position.display_id = _display_id;
_mouse_x = _mouse_y = ~0;
_display_id = -1;
_active_motion = false;
_marshallers->msgc_inputs_mouse_position(marshaller, &position);
}
void InputsChannel::on_mouse_motion(int dx, int dy, int buttons_state)
{
Lock lock(_motion_lock);
_mouse_buttons_state = buttons_state;
_mouse_dx += dx;
_mouse_dy += dy;
if (!_active_motion && _motion_count < SPICE_INPUT_MOTION_ACK_BUNCH * 2) {
_active_motion = true;
_motion_count++;
post_message(new MotionMessage(*this));
}
}
void InputsChannel::on_mouse_position(int x, int y, int buttons_state, int display_id)
{
Lock lock(_motion_lock);
_mouse_buttons_state = buttons_state;
_mouse_x = x;
_mouse_y = y;
_display_id = display_id;
if (!_active_motion && _motion_count < SPICE_INPUT_MOTION_ACK_BUNCH * 2) {
_active_motion = true;
_motion_count++;
post_message(new PositionMessage(*this));
}
}
void InputsChannel::on_migrate()
{
_motion_count = _active_motion ? 1 : 0;
}
void InputsChannel::on_mouse_down(int button, int buttons_state)
{
Message* message;
message = new Message(SPICE_MSGC_INPUTS_MOUSE_PRESS);
SpiceMsgcMousePress event;
event.button = button;
event.buttons_state = buttons_state;
_marshallers->msgc_inputs_mouse_press(message->marshaller(), &event);
post_message(message);
}
void InputsChannel::on_mouse_up(int button, int buttons_state)
{
Message* message;
message = new Message(SPICE_MSGC_INPUTS_MOUSE_RELEASE);
SpiceMsgcMouseRelease event;
event.button = button;
event.buttons_state = buttons_state;
_marshallers->msgc_inputs_mouse_release(message->marshaller(), &event);
post_message(message);
}
InputsChannel::KeyInfo InputsChannel::_scan_table[REDKEY_NUM_KEYS];
uint32_t InputsChannel::get_make_scan_code(RedKey key)
{
return _scan_table[key].make_scan;
}
uint32_t InputsChannel::get_break_scan_code(RedKey key)
{
return _scan_table[key].break_scan;
}
void InputsChannel::on_key_down(RedKey key)
{
uint32_t scan_code = get_make_scan_code(key);
if (!scan_code) {
LOG_WARN("no make code for %d", key);
return;
}
Message* message = new Message(SPICE_MSGC_INPUTS_KEY_DOWN);
SpiceMsgcKeyDown event;
event.code = scan_code;
_marshallers->msgc_inputs_key_down(message->marshaller(), &event);
post_message(message);
}
void InputsChannel::on_key_up(RedKey key)
{
uint32_t scan_code = get_break_scan_code(key);
if (!scan_code) {
LOG_WARN("no break code for %d", key);
return;
}
Message* message = new Message(SPICE_MSGC_INPUTS_KEY_UP);
SpiceMsgcKeyUp event;
event.code = scan_code;
_marshallers->msgc_inputs_key_up(message->marshaller(), &event);
post_message(message);
}
void InputsChannel::set_local_modifiers()
{
unsigned int modifiers = 0;
if (_modifiers & SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK) {
modifiers |= Platform::SCROLL_LOCK_MODIFIER;
}
if (_modifiers & SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK) {
modifiers |= Platform::NUM_LOCK_MODIFIER;
}
if (_modifiers & SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK) {
modifiers |= Platform::CAPS_LOCK_MODIFIER;
}
Platform::set_keyboard_lock_modifiers(modifiers);
}
void InputsChannel::on_focus_in()
{
Lock lock(_update_modifiers_lock);
_active_modifiers_event = false;
_on_focus_modifiers = Platform::get_keyboard_lock_modifiers();
#ifdef SYNC_REMOTE_MODIFIERS
Message* message = new Message(SPICE_MSGC_INPUTS_KEY_MODIFIERS);
SpiceMsgcKeyModifiers modifiers;
modifiers.modifiers = _on_focus_modifiers;
_marshallers->msgc_inputs_key_modifiers(message->marshaller(), &modifiers);
post_message(message);
#else
set_local_modifiers();
#endif
}
void InputsChannel::on_focus_out()
{
Lock lock(_update_modifiers_lock);
_active_modifiers_event = true;
#ifndef SYNC_REMOTE_MODIFIERS
_modifiers = _on_focus_modifiers;
set_local_modifiers();
#endif
}
void InputsChannel::init_scan_code(int index)
{
ASSERT((index & 0x80) == 0);
_scan_table[index].make_scan = index;
_scan_table[index].break_scan = index | 0x80;
}
void InputsChannel::init_korean_scan_code(int index)
{
_scan_table[index].make_scan = index;
_scan_table[index].break_scan = index;
}
void InputsChannel::init_escape_scan_code(int index)
{
ASSERT(((index - REDKEY_ESCAPE_BASE) & 0x80) == 0);
_scan_table[index].make_scan = 0xe0 | ((index - REDKEY_ESCAPE_BASE) << 8);
_scan_table[index].break_scan = _scan_table[index].make_scan | 0x8000;
}
void InputsChannel::init_pause_scan_code()
{
_scan_table[REDKEY_PAUSE].make_scan = 0x451de1;
_scan_table[REDKEY_PAUSE].break_scan = 0xc59de1;
}
void InputsChannel::init_scan_table()
{
memset(_scan_table, 0, sizeof(_scan_table));
init_scan_code(REDKEY_ESCAPE);
init_scan_code(REDKEY_1);
init_scan_code(REDKEY_2);
init_scan_code(REDKEY_3);
init_scan_code(REDKEY_4);
init_scan_code(REDKEY_5);
init_scan_code(REDKEY_6);
init_scan_code(REDKEY_7);
init_scan_code(REDKEY_8);
init_scan_code(REDKEY_9);
init_scan_code(REDKEY_0);
init_scan_code(REDKEY_MINUS);
init_scan_code(REDKEY_EQUALS);
init_scan_code(REDKEY_BACKSPACE);
init_scan_code(REDKEY_TAB);
init_scan_code(REDKEY_Q);
init_scan_code(REDKEY_W);
init_scan_code(REDKEY_E);
init_scan_code(REDKEY_R);
init_scan_code(REDKEY_T);
init_scan_code(REDKEY_Y);
init_scan_code(REDKEY_U);
init_scan_code(REDKEY_I);
init_scan_code(REDKEY_O);
init_scan_code(REDKEY_P);
init_scan_code(REDKEY_L_BRACKET);
init_scan_code(REDKEY_R_BRACKET);
init_scan_code(REDKEY_ENTER);
init_scan_code(REDKEY_L_CTRL);
init_scan_code(REDKEY_A);
init_scan_code(REDKEY_S);
init_scan_code(REDKEY_D);
init_scan_code(REDKEY_F);
init_scan_code(REDKEY_G);
init_scan_code(REDKEY_H);
init_scan_code(REDKEY_J);
init_scan_code(REDKEY_K);
init_scan_code(REDKEY_L);
init_scan_code(REDKEY_SEMICOLON);
init_scan_code(REDKEY_QUOTE);
init_scan_code(REDKEY_BACK_QUOTE);
init_scan_code(REDKEY_L_SHIFT);
init_scan_code(REDKEY_BACK_SLASH);
init_scan_code(REDKEY_Z);
init_scan_code(REDKEY_X);
init_scan_code(REDKEY_C);
init_scan_code(REDKEY_V);
init_scan_code(REDKEY_B);
init_scan_code(REDKEY_N);
init_scan_code(REDKEY_M);
init_scan_code(REDKEY_COMMA);
init_scan_code(REDKEY_PERIOD);
init_scan_code(REDKEY_SLASH);
init_scan_code(REDKEY_R_SHIFT);
init_scan_code(REDKEY_PAD_MULTIPLY);
init_scan_code(REDKEY_L_ALT);
init_scan_code(REDKEY_SPACE);
init_scan_code(REDKEY_CAPS_LOCK);
init_scan_code(REDKEY_F1);
init_scan_code(REDKEY_F2);
init_scan_code(REDKEY_F3);
init_scan_code(REDKEY_F4);
init_scan_code(REDKEY_F5);
init_scan_code(REDKEY_F6);
init_scan_code(REDKEY_F7);
init_scan_code(REDKEY_F8);
init_scan_code(REDKEY_F9);
init_scan_code(REDKEY_F10);
init_scan_code(REDKEY_NUM_LOCK);
init_scan_code(REDKEY_SCROLL_LOCK);
init_scan_code(REDKEY_PAD_7);
init_scan_code(REDKEY_PAD_8);
init_scan_code(REDKEY_PAD_9);
init_scan_code(REDKEY_PAD_MINUS);
init_scan_code(REDKEY_PAD_4);
init_scan_code(REDKEY_PAD_5);
init_scan_code(REDKEY_PAD_6);
init_scan_code(REDKEY_PAD_PLUS);
init_scan_code(REDKEY_PAD_1);
init_scan_code(REDKEY_PAD_2);
init_scan_code(REDKEY_PAD_3);
init_scan_code(REDKEY_PAD_0);
init_scan_code(REDKEY_PAD_POINT);
init_scan_code(REDKEY_EUROPEAN);
init_scan_code(REDKEY_F11);
init_scan_code(REDKEY_F12);
init_scan_code(REDKEY_JAPANESE_HIRAGANA_KATAKANA);
init_scan_code(REDKEY_JAPANESE_BACKSLASH);
init_scan_code(REDKEY_JAPANESE_HENKAN);
init_scan_code(REDKEY_JAPANESE_MUHENKAN);
init_scan_code(REDKEY_JAPANESE_YEN);
init_korean_scan_code(REDKEY_KOREAN_HANGUL);
init_korean_scan_code(REDKEY_KOREAN_HANGUL_HANJA);
init_escape_scan_code(REDKEY_ESCAPE_BASE);
init_escape_scan_code(REDKEY_PAD_ENTER);
init_escape_scan_code(REDKEY_R_CTRL);
init_escape_scan_code(REDKEY_MUTE);
init_escape_scan_code(REDKEY_FAKE_L_SHIFT);
init_escape_scan_code(REDKEY_VOLUME_DOWN);
init_escape_scan_code(REDKEY_VOLUME_UP);
init_escape_scan_code(REDKEY_PAD_DIVIDE);
init_escape_scan_code(REDKEY_FAKE_R_SHIFT);
init_escape_scan_code(REDKEY_CTRL_PRINT_SCREEN);
init_escape_scan_code(REDKEY_R_ALT);
init_escape_scan_code(REDKEY_CTRL_BREAK);
init_escape_scan_code(REDKEY_HOME);
init_escape_scan_code(REDKEY_UP);
init_escape_scan_code(REDKEY_PAGEUP);
init_escape_scan_code(REDKEY_LEFT);
init_escape_scan_code(REDKEY_RIGHT);
init_escape_scan_code(REDKEY_END);
init_escape_scan_code(REDKEY_DOWN);
init_escape_scan_code(REDKEY_PAGEDOWN);
init_escape_scan_code(REDKEY_INSERT);
init_escape_scan_code(REDKEY_DELETE);
init_escape_scan_code(REDKEY_LEFT_CMD);
init_escape_scan_code(REDKEY_RIGHT_CMD);
init_escape_scan_code(REDKEY_MENU);
init_pause_scan_code();
}
class InitGlobals {
public:
InitGlobals()
{
InputsChannel::init_scan_table();
}
};
static InitGlobals init_globals;
class InputsFactory: public ChannelFactory {
public:
InputsFactory() : ChannelFactory(SPICE_CHANNEL_INPUTS) {}
virtual RedChannel* construct(RedClient& client, uint32_t id)
{
return new InputsChannel(client, id);
}
};
static InputsFactory factory;
ChannelFactory& InputsChannel::Factory()
{
return factory;
}

View File

@ -1,96 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_INPUTS_CHANNEL
#define _H_INPUTS_CHANNEL
#include "red_channel.h"
#include "inputs_handler.h"
class ChannelFactory;
class InputsChannel: public RedChannel, public KeyHandler, public MouseHandler {
public:
InputsChannel(RedClient& client, uint32_t id);
virtual ~InputsChannel();
virtual void on_mouse_motion(int dx, int dy, int buttons_state);
virtual void on_mouse_down(int button, int buttons_state);
virtual void on_mouse_up(int button, int buttons_state);
virtual void on_key_down(RedKey key);
virtual void on_key_up(RedKey key);
virtual void on_focus_in();
virtual void on_focus_out();
void on_mouse_position(int x, int y, int buttons_state, int display_id);
static ChannelFactory& Factory();
protected:
virtual void on_connect();
virtual void on_disconnect();
virtual void on_migrate();
private:
void marshall_motion_event(SpiceMarshaller *marshaller);
void marshall_position_event(SpiceMarshaller *marshaller);
void set_local_modifiers();
void handle_init(RedPeer::InMessage* message);
void handle_modifiers(RedPeer::InMessage* message);
void handle_motion_ack(RedPeer::InMessage* message);
static uint32_t get_make_scan_code(RedKey key);
static uint32_t get_break_scan_code(RedKey key);
static void init_scan_code(int index);
static void init_korean_scan_code(int index);
static void init_escape_scan_code(int index);
static void init_pause_scan_code();
static void init_scan_table();
private:
Mutex _motion_lock;
int _mouse_buttons_state;
int _mouse_dx;
int _mouse_dy;
unsigned int _mouse_x;
unsigned int _mouse_y;
int _display_id;
bool _active_motion;
int _motion_count;
uint32_t _modifiers;
uint32_t _on_focus_modifiers;
Mutex _update_modifiers_lock;
bool _active_modifiers_event;
struct KeyInfo {
uint32_t make_scan;
uint32_t break_scan;
};
static KeyInfo _scan_table[REDKEY_NUM_KEYS];
friend class InitGlobals;
friend class MotionMessage;
friend class PositionMessage;
friend class KeyModifiersEvent;
friend class SetInputsHandlerEvent;
friend class RemoveInputsHandlerEvent;
};
#endif

View File

@ -1,42 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_INPUTS_HANDLER
#define _H_INPUTS_HANDLER
#include "red_key.h"
class KeyHandler {
public:
virtual ~KeyHandler() {}
virtual void on_key_down(RedKey key) {}
virtual void on_key_up(RedKey key) {}
virtual void on_char(uint32_t ch) {}
virtual void on_focus_in() {}
virtual void on_focus_out() {}
virtual bool permit_focus_loss() { return true;}
};
class MouseHandler {
public:
virtual ~MouseHandler() {}
virtual void on_mouse_motion(int dx, int dy, int buttons_state) {}
virtual void on_mouse_down(int button, int buttons_state) {}
virtual void on_mouse_up(int button, int buttons_state) {}
};
#endif

View File

@ -1,153 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "jpeg_decoder.h"
#include "debug.h"
#include "utils.h"
#if !defined(jpeg_boolean)
#define jpeg_boolean boolean
#endif
static void op_begin_decode(SpiceJpegDecoder *decoder,
uint8_t* data,
int data_size,
int* out_width,
int* out_height)
{
JpegDecoder* _decoder = static_cast<JpegDecoder*>(decoder);
_decoder->begin_decode(data, data_size, *out_width, *out_height);
}
static void op_decode(SpiceJpegDecoder *decoder,
uint8_t* dest,
int stride,
int format)
{
JpegDecoder* _decoder = static_cast<JpegDecoder*>(decoder);
_decoder->decode(dest, stride, format);
}
extern "C" {
static void jpeg_decoder_init_source(j_decompress_ptr cinfo)
{
}
static SPICE_GNUC_NORETURN jpeg_boolean jpeg_decoder_fill_input_buffer(j_decompress_ptr cinfo)
{
PANIC("no more data for jpeg");
}
static void jpeg_decoder_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
{
ASSERT(num_bytes < (long)cinfo->src->bytes_in_buffer);
cinfo->src->next_input_byte += num_bytes;
cinfo->src->bytes_in_buffer -= num_bytes;
}
static void jpeg_decoder_term_source (j_decompress_ptr cinfo)
{
return;
}
}
JpegDecoder::JpegDecoder()
: _data (NULL)
, _data_size (0)
{
_cinfo.err = jpeg_std_error(&_jerr);
jpeg_create_decompress(&_cinfo);
_cinfo.src = &_jsrc;
_cinfo.src->init_source = jpeg_decoder_init_source;
_cinfo.src->fill_input_buffer = jpeg_decoder_fill_input_buffer;
_cinfo.src->skip_input_data = jpeg_decoder_skip_input_data;
_cinfo.src->resync_to_restart = jpeg_resync_to_restart;
_cinfo.src->term_source = jpeg_decoder_term_source;
static SpiceJpegDecoderOps decoder_ops = {
op_begin_decode,
op_decode,
};
ops = &decoder_ops;
}
JpegDecoder::~JpegDecoder()
{
jpeg_destroy_decompress(&_cinfo);
}
void JpegDecoder::begin_decode(uint8_t* data, int data_size, int& out_width, int& out_height)
{
ASSERT(data);
ASSERT(data_size);
if (_data) {
jpeg_abort_decompress(&_cinfo);
}
_data = data;
_data_size = data_size;
_cinfo.src->next_input_byte = _data;
_cinfo.src->bytes_in_buffer = _data_size;
jpeg_read_header(&_cinfo, TRUE);
_cinfo.out_color_space = JCS_RGB;
_width = _cinfo.image_width;
_height = _cinfo.image_height;
out_width = _width;
out_height = _height;
}
void JpegDecoder::decode(uint8_t *dest, int stride, int format)
{
uint8_t* scan_line = new uint8_t[_width*3];
RGBConverter* rgb_converter;
switch (format) {
case SPICE_BITMAP_FMT_24BIT:
rgb_converter = &_rgb2bgr;
break;
case SPICE_BITMAP_FMT_32BIT:
rgb_converter = &_rgb2bgrx;
break;
default:
THROW("bad bitmap format, %d", format);
}
jpeg_start_decompress(&_cinfo);
for (int row = 0; row < _height; row++) {
jpeg_read_scanlines(&_cinfo, &scan_line, 1);
rgb_converter->convert(scan_line, dest, _width);
dest += stride;
}
delete [] scan_line;
jpeg_finish_decompress(&_cinfo);
}

View File

@ -1,96 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_JPEG_DECODER
#define _H_JPEG_DECODER
#include "common.h"
#include "red_canvas_base.h"
#if defined(WIN32) && !defined(__MINGW32__)
/* We need some hacks to avoid warnings from the jpeg headers */
#define XMD_H
#undef FAR
#endif
extern "C" {
#include <jpeglib.h>
#ifdef HAVE_STDLIB_H
/* on mingw, there is a hack,
and we also include config.h from spice-common, which redefine it */
#undef HAVE_STDLIB_H
#endif
}
class RGBConverter {
public:
virtual ~RGBConverter() {}
virtual void convert(uint8_t* src, uint8_t* dest, int width) = 0;
};
class RGBToBGRConverter : public RGBConverter {
public:
void convert(uint8_t* src, uint8_t* dest, int width)
{
for (int x = 0; x < width; x++) {
*dest++ = src[2];
*dest++ = src[1];
*dest++ = src[0];
src += 3;
}
}
};
class RGBToBGRXConverter : public RGBConverter {
public:
void convert(uint8_t* src, uint8_t* dest, int width)
{
for (int x = 0; x < width; x++) {
*dest++ = src[2];
*dest++ = src[1];
*dest++ = src[0];
*dest++ = 0;
src += 3;
}
}
};
class JpegDecoder : public SpiceJpegDecoder {
public:
JpegDecoder();
~JpegDecoder();
void begin_decode(uint8_t* data, int data_size, int& out_width, int& out_height);
/* format is SPICE_BITMAP_FMT_<X> for the dest; currently, only
x=32BIT and x=24BIT are supported */
void decode(uint8_t* dest, int stride, int format);
private:
struct jpeg_decompress_struct _cinfo;
struct jpeg_error_mgr _jerr;
struct jpeg_source_mgr _jsrc;
uint8_t* _data;
int _data_size;
int _width;
int _height;
RGBToBGRConverter _rgb2bgr;
RGBToBGRXConverter _rgb2bgrx;
};
#endif

View File

@ -1,147 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "menu.h"
#include "utils.h"
#include "debug.h"
Menu::Menu(CommandTarget& target, const std::string& name, int id)
: _refs (1)
, _target (target)
, _name (name)
, _id (id)
{
}
Menu::~Menu()
{
clear();
}
void Menu::add_item(MenuItem& item)
{
int pos = _items.size();
_items.resize(pos + 1);
_items[pos] = item;
}
void Menu::add_command(const std::string& name, int cmd_id, int state)
{
MenuCommand* cmd = new MenuCommand(name, cmd_id, state);
MenuItem item;
item.type = MENU_ITEM_TYPE_COMMAND;
item.obj = cmd;
add_item(item);
}
void Menu::add_separator()
{
MenuItem item;
item.type = MENU_ITEM_TYPE_SEPARATOR;
item.obj = NULL;
add_item(item);
}
void Menu::add_sub(Menu* menu)
{
ASSERT(menu);
MenuItem item;
item.type = MENU_ITEM_TYPE_MENU;
item.obj = menu->ref();
add_item(item);
}
void Menu::remove_command(int cmd_id)
{
for (unsigned int i = 0; i < _items.size(); i++) {
if (_items[i].type == MENU_ITEM_TYPE_COMMAND &&
((MenuCommand*)_items[i].obj)->get_cmd_id() == cmd_id) {
delete (MenuCommand*)_items[i].obj;
_items.erase(_items.begin() + i);
return;
}
}
}
void Menu::remove_sub(Menu* menu)
{
for (unsigned int i = 0; i < _items.size(); i++) {
if (_items[i].type == MENU_ITEM_TYPE_MENU && (Menu*)_items[i].obj == menu) {
((Menu*)_items[i].obj)->unref();
_items.erase(_items.begin() + i);
return;
}
}
}
Menu::ItemType Menu::item_type_at(int pos)
{
if (pos >= (int)_items.size()) {
return MENU_ITEM_TYPE_INVALID;
}
return _items[pos].type;
}
void Menu::command_at(int pos, std::string& name, int& cmd_id, int& state)
{
if (_items[pos].type != MENU_ITEM_TYPE_COMMAND) {
THROW("incorrect item type");
}
MenuCommand* cmd = (MenuCommand*)_items[pos].obj;
name = cmd->get_name();
cmd_id = cmd->get_cmd_id();
state = cmd->get_state();
}
Menu* Menu::sub_at(int pos)
{
if (_items[pos].type != MENU_ITEM_TYPE_MENU) {
THROW("incorrect item type");
}
return ((Menu*)_items[pos].obj)->ref();
}
Menu* Menu::find_sub(int id)
{
Menu* sub;
if (_id == id) {
return ref();
}
for (unsigned int i = 0; i < _items.size(); i++) {
if (_items[i].type == MENU_ITEM_TYPE_MENU && (sub = ((Menu*)_items[i].obj)->find_sub(id))) {
return sub;
}
}
return NULL;
}
void Menu::clear()
{
for (unsigned int i = 0; i < _items.size(); i++) {
if (_items[i].type == MENU_ITEM_TYPE_COMMAND) {
delete (MenuCommand*)_items[i].obj;
} else if (_items[i].type == MENU_ITEM_TYPE_MENU) {
((Menu*)_items[i].obj)->unref();
}
}
_items.clear();
}

View File

@ -1,102 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MENU
#define _H_MENU
class CommandTarget {
public:
virtual void do_command(int command) = 0;
virtual ~CommandTarget() {}
};
class Menu {
public:
Menu(CommandTarget& target, const std::string& name, int id = 0);
enum ItemType {
MENU_ITEM_TYPE_INVALID,
MENU_ITEM_TYPE_COMMAND,
MENU_ITEM_TYPE_MENU,
MENU_ITEM_TYPE_SEPARATOR,
};
enum ItemState {
MENU_ITEM_STATE_CHECKED = 1 << 0,
MENU_ITEM_STATE_DIM = 1 << 1,
};
Menu* ref() { _refs++; return this;}
void unref() { if (!--_refs) delete this;}
void set_name(const std::string& name) { _name = name;}
const std::string& get_name() { return _name;}
CommandTarget& get_target() { return _target;}
int get_id() { return _id;}
void add_command(const std::string& name, int cmd_id, int state = 0);
void add_separator();
void add_sub(Menu* sub);
void remove_command(int cmd_id);
void remove_sub(Menu* menu);
ItemType item_type_at(int pos);
void command_at(int pos, std::string& name, int& cmd_id, int& state);
Menu* sub_at(int pos);
Menu* find_sub(int id);
void clear();
private:
virtual ~Menu();
class MenuCommand {
public:
MenuCommand(const std::string& name, int cmd_id, int state)
: _name (name)
, _cmd_id (cmd_id)
, _state (state)
{
}
const std::string& get_name() { return _name;}
int get_cmd_id() { return _cmd_id;}
int get_state() { return _state;}
private:
std::string _name;
int _cmd_id;
int _state;
};
struct MenuItem {
ItemType type;
void *obj;
};
void add_item(MenuItem& item);
private:
int _refs;
CommandTarget& _target;
std::string _name;
std::vector<MenuItem> _items;
int _id;
};
#endif

View File

@ -1,277 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "debug.h"
#include "utils.h"
#include "mjpeg_decoder.h"
#if !defined(jpeg_boolean)
#define jpeg_boolean boolean
#endif
enum {
STATE_READ_HEADER,
STATE_START_DECOMPRESS,
STATE_READ_SCANLINES,
STATE_FINISH_DECOMPRESS
};
extern "C" {
static void init_source(j_decompress_ptr cinfo)
{
}
static jpeg_boolean fill_input_buffer(j_decompress_ptr cinfo)
{
return FALSE;
}
void mjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
{
MJpegDecoder *decoder = (MJpegDecoder *)cinfo;
if (num_bytes > 0) {
if (cinfo->src->bytes_in_buffer >= (size_t)num_bytes) {
cinfo->src->next_input_byte += (size_t) num_bytes;
cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
} else {
decoder->_extra_skip = num_bytes - cinfo->src->bytes_in_buffer;
cinfo->src->bytes_in_buffer = 0;
}
}
}
static void term_source (j_decompress_ptr cinfo)
{
return;
}
}
MJpegDecoder::MJpegDecoder(int width, int height,
int stride,
uint8_t *frame,
bool back_compat) :
_data(NULL)
, _data_size(0)
, _data_start(0)
, _data_end(0)
, _extra_skip(0)
, _width(width)
, _height(height)
, _stride(stride)
, _frame(frame)
, _back_compat(back_compat)
, _y(0)
, _state(0)
{
memset(&_cinfo, 0, sizeof(_cinfo));
_cinfo.err = jpeg_std_error (&_jerr);
jpeg_create_decompress (&_cinfo);
_cinfo.src = &_jsrc;
_cinfo.src->init_source = init_source;
_cinfo.src->fill_input_buffer = fill_input_buffer;
_cinfo.src->skip_input_data = mjpeg_skip_input_data;
_cinfo.src->resync_to_restart = jpeg_resync_to_restart;
_cinfo.src->term_source = term_source;
_scanline = new uint8_t[width * 3];
}
MJpegDecoder::~MJpegDecoder()
{
jpeg_destroy_decompress(&_cinfo);
delete [] _scanline;
if (_data) {
delete [] _data;
}
}
void MJpegDecoder::convert_scanline(void)
{
uint32_t *row;
uint32_t c;
uint8_t *s;
unsigned x;
ASSERT(_width % 2 == 0);
ASSERT(_height % 2 == 0);
row = (uint32_t *)(_frame + _y * _stride);
s = _scanline;
if (_back_compat) {
/* We need to check for the old major and for backwards compat
a) swap r and b (done)
b) to-yuv with right values and then from-yuv with old wrong values (TODO)
*/
for (x = 0; x < _width; x++) {
c = s[2] << 16 | s[1] << 8 | s[0];
s += 3;
*row++ = c;
}
} else {
for (x = 0; x < _width; x++) {
c = s[0] << 16 | s[1] << 8 | s[2];
s += 3;
*row++ = c;
}
}
}
void MJpegDecoder::append_data(uint8_t *data, size_t length)
{
uint8_t *new_data;
size_t data_len;
if (length == 0) {
return;
}
if (_data_size - _data_end < length) {
/* Can't fits in tail, need to make space */
data_len = _data_end - _data_start;
if (_data_size - data_len < length) {
/* Can't fit at all, grow a bit */
_data_size = _data_size + length * 2;
new_data = new uint8_t[_data_size];
memcpy (new_data, _data + _data_start, data_len);
delete [] _data;
_data = new_data;
} else {
/* Just needs to compact */
memmove (_data, _data + _data_start, data_len);
}
_data_start = 0;
_data_end = data_len;
}
memcpy (_data + _data_end, data, length);
_data_end += length;
}
bool MJpegDecoder::decode_data(uint8_t *data, size_t length)
{
bool got_picture;
int res;
got_picture = false;
if (_extra_skip > 0) {
if (_extra_skip >= length) {
_extra_skip -= length;
return false;
} else {
data += _extra_skip;
length -= _extra_skip;
_extra_skip = 0;
}
}
if (_data_end - _data_start == 0) {
/* No current data, pass in without copy */
_jsrc.next_input_byte = data;
_jsrc.bytes_in_buffer = length;
} else {
/* Need to combine the new and old data */
append_data(data, length);
_jsrc.next_input_byte = _data + _data_start;
_jsrc.bytes_in_buffer = _data_end - _data_start;
}
switch (_state) {
case STATE_READ_HEADER:
res = jpeg_read_header(&_cinfo, TRUE);
if (res == JPEG_SUSPENDED) {
break;
}
_cinfo.do_fancy_upsampling = FALSE;
_cinfo.do_block_smoothing = FALSE;
_cinfo.out_color_space = JCS_RGB;
PANIC_ON(_cinfo.image_width != _width);
PANIC_ON(_cinfo.image_height != _height);
_state = STATE_START_DECOMPRESS;
/* fall through */
case STATE_START_DECOMPRESS:
res = jpeg_start_decompress (&_cinfo);
if (!res) {
break;
}
_state = STATE_READ_SCANLINES;
/* fall through */
case STATE_READ_SCANLINES:
res = 0;
while (_y < _height) {
res = jpeg_read_scanlines(&_cinfo, &_scanline, 1);
if (res == 0) {
break;
}
convert_scanline();
_y++;
}
if (res == 0) {
break;
}
_state = STATE_FINISH_DECOMPRESS;
/* fall through */
case STATE_FINISH_DECOMPRESS:
res = jpeg_finish_decompress (&_cinfo);
if (!res) {
break;
}
_y = 0;
_state = STATE_READ_HEADER;
got_picture = true;
break;
}
if (_jsrc.next_input_byte == data) {
/* We read directly from the user, store remaining data in
buffer for next time */
size_t read_size = _jsrc.next_input_byte - data;
append_data(data + read_size, length - read_size);
} else {
_data_start = _jsrc.next_input_byte - _data;
_data_end = _data_start + _jsrc.bytes_in_buffer;
}
return got_picture;
}

View File

@ -1,74 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MJPEG_DECODER
#define _H_MJPEG_DECODER
#include "common.h"
#ifdef WIN32
/* We need some hacks to avoid warnings from the jpeg headers */
#define XMD_H
#undef FAR
#endif
extern "C" {
#include <jpeglib.h>
}
extern "C" {
void mjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes);
}
class MJpegDecoder {
public:
MJpegDecoder(int width, int height, int stride,
uint8_t *frame, bool back_compat);
~MJpegDecoder();
bool decode_data(uint8_t *data, size_t length);
private:
friend void mjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes);
void convert_scanline(void);
void append_data(uint8_t *data, size_t length);
struct jpeg_decompress_struct _cinfo;
struct jpeg_error_mgr _jerr;
struct jpeg_source_mgr _jsrc;
uint8_t *_data;
size_t _data_size;
size_t _data_start;
size_t _data_end;
size_t _extra_skip;
unsigned _width;
unsigned _height;
int _stride;
uint8_t *_frame;
bool _back_compat;
unsigned _y;
uint8_t *_scanline;
int _state;
};
#endif

View File

@ -1,49 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "monitor.h"
#include "debug.h"
#include "platform.h"
uint32_t Monitor::self_monitors_change = 0;
Monitor::Monitor(int id)
: _id (id)
, _free (true)
{
}
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();
}

View File

@ -1,57 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_MONITOR
#define _H_MONITOR
#include "common/draw.h"
class Monitor {
public:
Monitor(int id);
int get_id() { return _id;}
bool is_free() { return _free;}
void set_free() {_free = true;}
void set_used() {_free = false;}
void set_mode(int width, int height);
void restore();
virtual int get_depth() = 0;
virtual SpicePoint get_position() = 0;
virtual SpicePoint get_size() const = 0;
virtual bool is_out_of_sync() = 0;
virtual int get_screen_id() = 0;
static bool is_self_change();
protected:
virtual ~Monitor() {}
virtual void do_set_mode(int width, int height) = 0;
virtual void do_restore() = 0;
private:
int _id;
bool _free;
protected:
static uint32_t self_monitors_change;
friend class Platform;
};
#endif

View File

@ -1,58 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_PIXELS_SOURCE
#define _H_PIXELS_SOURCE
#include "common/draw.h"
#define PIXELES_SOURCE_OPAQUE_SIZE (20 * sizeof(void*))
class PixelsSource {
public:
PixelsSource();
virtual ~PixelsSource();
virtual SpicePoint get_size() = 0;
void set_origin(int x, int y) { _origin.x = x; _origin.y = y;}
const SpicePoint& get_origin() { return _origin;}
protected:
const uint8_t* get_opaque() const { return _opaque;}
private:
SpicePoint _origin;
uint8_t _opaque[PIXELES_SOURCE_OPAQUE_SIZE];
friend class RedDrawable;
};
class ImageFromRes: public PixelsSource {
public:
ImageFromRes(int res_id);
virtual ~ImageFromRes();
virtual SpicePoint get_size();
};
class AlphaImageFromRes: public PixelsSource {
public:
AlphaImageFromRes(int res_id);
virtual ~AlphaImageFromRes();
virtual SpicePoint get_size();
};
#endif

View File

@ -1,205 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_PLATFORM
#define _H_PLATFORM
#include "cursor.h"
#include "process_loop.h"
#include "event_sources.h"
#include "process_loop.h"
class WaveRecordAbstract;
class WavePlaybackAbstract;
class Icon;
class Monitor;
typedef std::list<Monitor*> MonitorsList;
class Platform {
public:
static void init();
static void set_process_loop(ProcessLoop& main_process_loop);
static void msleep(unsigned int millisec);
static void yield();
static uint64_t get_monolithic_time();
static void get_temp_dir(std::string& path);
static void get_app_data_dir(std::string& path, const std::string& app_name);
static void path_append(std::string& path, const std::string& partial_path);
static uint64_t get_process_id();
static uint64_t get_thread_id();
static SPICE_GNUC_PRINTF(1, 2) void term_printf(const char* format, ...);
static void error_beep();
static const MonitorsList& init_monitors();
static void destroy_monitors();
static bool is_monitors_pos_valid();
static void send_quit_request();
enum ThreadPriority {
PRIORITY_INVALID,
PRIORITY_TIME_CRITICAL,
PRIORITY_HIGH,
PRIORITY_ABOVE_NORMAL,
PRIORITY_NORMAL,
PRIORITY_BELOW_NORMAL,
PRIORITY_LOW,
PRIORITY_IDLE,
};
static void set_thread_priority(void *thread, ThreadPriority priority);
class RecordClient;
static WaveRecordAbstract* create_recorder(RecordClient& client,
uint32_t samples_per_sec,
uint32_t bits_per_sample,
uint32_t channels,
uint32_t frame_size);
static WavePlaybackAbstract* create_player(uint32_t samples_per_sec,
uint32_t bits_per_sample,
uint32_t channels,
uint32_t frame_size);
enum {
SCROLL_LOCK_MODIFIER_SHIFT,
NUM_LOCK_MODIFIER_SHIFT,
CAPS_LOCK_MODIFIER_SHIFT,
SCROLL_LOCK_MODIFIER = (1 << SCROLL_LOCK_MODIFIER_SHIFT),
NUM_LOCK_MODIFIER = (1 << NUM_LOCK_MODIFIER_SHIFT),
CAPS_LOCK_MODIFIER = (1 << CAPS_LOCK_MODIFIER_SHIFT),
};
static uint32_t get_keyboard_lock_modifiers();
static void set_keyboard_lock_modifiers(uint32_t modifiers);
enum {
L_SHIFT_MODIFIER_SHIFT,
R_SHIFT_MODIFIER_SHIFT,
L_CTRL_MODIFIER_SHIFT,
R_CTRL_MODIFIER_SHIFT,
L_ALT_MODIFIER_SHIFT,
R_ALT_MODIFIER_SHIFT,
L_SHIFT_MODIFIER = (1 << L_SHIFT_MODIFIER_SHIFT),
R_SHIFT_MODIFIER = (1 << R_SHIFT_MODIFIER_SHIFT),
L_CTRL_MODIFIER = (1 << L_CTRL_MODIFIER_SHIFT),
R_CTRL_MODIFIER = (1 << R_CTRL_MODIFIER_SHIFT),
L_ALT_MODIFIER = (1 << L_ALT_MODIFIER_SHIFT),
R_ALT_MODIFIER = (1 << R_ALT_MODIFIER_SHIFT),
};
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();
static Icon* load_icon(int id);
class EventListener;
static void set_event_listener(EventListener* listener);
class DisplayModeListener;
static void set_display_mode_listner(DisplayModeListener* listener);
class ClipboardListener;
static void set_clipboard_listener(ClipboardListener* listener);
static bool on_clipboard_grab(uint32_t *types, uint32_t type_count);
static bool on_clipboard_notify(uint32_t type, const uint8_t* data, int32_t size);
static bool on_clipboard_request(uint32_t type);
static void on_clipboard_release();
enum { owner_none, owner_guest, owner_client };
static void set_clipboard_owner(int new_owner);
static int get_clipboard_owner() { return _clipboard_owner; }
private:
static void set_clipboard_owner_unlocked(int new_owner);
static int _clipboard_owner;
};
class Platform::EventListener {
public:
virtual ~EventListener() {}
virtual void on_app_activated() = 0;
virtual void on_app_deactivated() = 0;
virtual void on_monitors_change() = 0;
};
class Platform::ClipboardListener {
public:
virtual ~ClipboardListener() {}
virtual void on_clipboard_grab(uint32_t *types, uint32_t type_count) = 0;
virtual void on_clipboard_request(uint32_t type) = 0;
virtual void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size) = 0;
virtual void on_clipboard_release() = 0;
};
class Platform::RecordClient {
public:
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;
virtual void remove_event_source(EventSources::Trigger& evnet_source) = 0;
virtual void push_frame(uint8_t *frame) = 0;
};
class Platform::DisplayModeListener {
public:
virtual ~DisplayModeListener() {}
virtual void on_display_mode_change() = 0;
};
class NamedPipe {
public:
typedef unsigned long ListenerRef;
typedef unsigned long ConnectionRef;
static const ConnectionRef INVALID_CONNECTION = ~0;
class ConnectionInterface {
public:
ConnectionInterface() : _opaque (INVALID_CONNECTION) {}
virtual ~ConnectionInterface() {}
virtual void bind(ConnectionRef conn_ref) = 0;
virtual void on_data() = 0;
protected:
ConnectionRef _opaque;
};
class ListenerInterface {
public:
virtual ~ListenerInterface() {}
virtual ConnectionInterface &create() = 0;
};
static ListenerRef create(const char *name, ListenerInterface& listener_interface);
static void destroy(ListenerRef listener_ref);
static void destroy_connection(ConnectionRef conn_ref);
static int32_t read(ConnectionRef conn_ref, uint8_t *buf, int32_t size);
static int32_t write(ConnectionRef conn_ref, const uint8_t *buf, int32_t size);
};
#endif

View File

@ -1,364 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "red_client.h"
#include "audio_channels.h"
#include "audio_devices.h"
//#define WAVE_CAPTURE
#ifdef WAVE_CAPTURE
#include <fcntl.h>
#define WAVE_BUF_SIZE (1024 * 1024 * 20)
typedef struct __attribute__ ((__packed__)) ChunkHeader {
uint32_t id;
uint32_t size;
} ChunkHeader;
typedef struct __attribute__ ((__packed__)) FormatInfo {
uint16_t compression_code;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t average_bytes_per_second;
uint16_t block_align;
uint16_t bits_per_sample;
//uint16_t extra_format_bytes;
//uint8_t extra[0];
} FormatInfo;
static uint8_t* wave_buf = NULL;
static uint8_t* wave_now = NULL;
static uint8_t* wave_end = NULL;
static bool wave_blocked = false;
static void write_all(int fd, uint8_t* data, uint32_t size)
{
while (size) {
int n = write(fd, data, size);
if (n == -1) {
if (errno != EINTR) {
throw Exception(fmt("%s: failed") % __FUNCTION__);
}
} else {
data += n;
size -= n;
}
}
}
static void write_wave()
{
static uint32_t file_id = 0;
char file_name[100];
ChunkHeader header;
FormatInfo format;
if (wave_buf == wave_now) {
return;
}
sprintf(file_name, "/tmp/%u.wav", ++file_id);
int fd = open(file_name, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd == -1) {
DBG(0, fmt("open file %s failed") % file_name);
return;
}
memcpy((char *)&header.id, "RIFF", 4);
header.size = 4;
write_all(fd, (uint8_t *)&header, sizeof(header));
write_all(fd, (uint8_t *)"WAVE", 4);
memcpy((char *)&header.id, "fmt ", 4);
header.size = sizeof(format);
write_all(fd, (uint8_t *)&header, sizeof(header));
format.compression_code = 1;
format.num_channels = 2;
format.sample_rate = 44100;
format.average_bytes_per_second = format.sample_rate * 4;
format.block_align = 4;
format.bits_per_sample = 16;
write_all(fd, (uint8_t *)&format, sizeof(format));
memcpy((char *)&header.id, "data", 4);
header.size = wave_now - wave_buf;
write_all(fd, (uint8_t *)&header, sizeof(header));
write_all(fd, wave_buf, header.size);
close(fd);
}
static void init_wave()
{
if (!wave_buf) {
wave_buf = new uint8_t[WAVE_BUF_SIZE];
}
wave_now = wave_buf;
wave_end = wave_buf + WAVE_BUF_SIZE;
}
static void start_wave()
{
wave_blocked = false;
wave_now = wave_buf;
}
static void put_wave_data(uint8_t *data, uint32_t size)
{
if (wave_blocked || size > wave_end - wave_now) {
wave_blocked = true;
return;
}
memcpy((void *)wave_now, (void *)data, size);
wave_now += size;
}
static void end_wave()
{
write_wave();
}
#endif
class PlaybackHandler: public MessageHandlerImp<PlaybackChannel, SPICE_CHANNEL_PLAYBACK> {
public:
PlaybackHandler(PlaybackChannel& channel)
: MessageHandlerImp<PlaybackChannel, SPICE_CHANNEL_PLAYBACK>(channel) {}
};
PlaybackChannel::PlaybackChannel(RedClient& client, uint32_t id)
: RedChannel(client, SPICE_CHANNEL_PLAYBACK, id, new PlaybackHandler(*this),
Platform::PRIORITY_HIGH)
, _wave_player (NULL)
, _mode (SPICE_AUDIO_DATA_MODE_INVALID)
, _codec(NULL)
, _playing (false)
{
#ifdef WAVE_CAPTURE
init_wave();
#endif
PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
handler->set_handler(SPICE_MSG_MIGRATE, &PlaybackChannel::handle_migrate);
handler->set_handler(SPICE_MSG_SET_ACK, &PlaybackChannel::handle_set_ack);
handler->set_handler(SPICE_MSG_PING, &PlaybackChannel::handle_ping);
handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &PlaybackChannel::handle_wait_for_channels);
handler->set_handler(SPICE_MSG_DISCONNECTING, &PlaybackChannel::handle_disconnect);
handler->set_handler(SPICE_MSG_NOTIFY, &PlaybackChannel::handle_notify);
handler->set_handler(SPICE_MSG_PLAYBACK_MODE, &PlaybackChannel::handle_mode);
if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1, SND_CODEC_ANY_FREQUENCY))
set_capability(SPICE_PLAYBACK_CAP_CELT_0_5_1);
if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, SND_CODEC_ANY_FREQUENCY))
set_capability(SPICE_PLAYBACK_CAP_OPUS);
}
void PlaybackChannel::clear()
{
if (_wave_player) {
_playing = false;
_wave_player->stop();
delete _wave_player;
_wave_player = NULL;
}
_mode = SPICE_AUDIO_DATA_MODE_INVALID;
snd_codec_destroy(&_codec);
}
void PlaybackChannel::on_disconnect()
{
clear();
}
PlaybackChannel::~PlaybackChannel(void)
{
clear();
}
bool PlaybackChannel::abort(void)
{
return (!_wave_player || _wave_player->abort()) && RedChannel::abort();
}
void PlaybackChannel::set_data_handler()
{
PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
if (_mode == SPICE_AUDIO_DATA_MODE_RAW) {
handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_raw_data);
} else if (snd_codec_is_capable(_mode, SND_CODEC_ANY_FREQUENCY)) {
handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::handle_compressed_data);
} else {
THROW("invalid mode");
}
}
void PlaybackChannel::handle_mode(RedPeer::InMessage* message)
{
SpiceMsgPlaybackMode* playback_mode = (SpiceMsgPlaybackMode*)message->data();
if (playback_mode->mode != SPICE_AUDIO_DATA_MODE_RAW
&& !snd_codec_is_capable(playback_mode->mode, SND_CODEC_ANY_FREQUENCY) ) {
THROW("invalid mode");
}
_mode = playback_mode->mode;
if (_playing) {
set_data_handler();
return;
}
PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
handler->set_handler(SPICE_MSG_PLAYBACK_START, &PlaybackChannel::handle_start);
}
void PlaybackChannel::null_handler(RedPeer::InMessage* message)
{
}
void PlaybackChannel::disable()
{
PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
handler->set_handler(SPICE_MSG_PLAYBACK_START, &PlaybackChannel::null_handler);
handler->set_handler(SPICE_MSG_PLAYBACK_STOP, &PlaybackChannel::null_handler);
handler->set_handler(SPICE_MSG_PLAYBACK_MODE, &PlaybackChannel::null_handler);
handler->set_handler(SPICE_MSG_PLAYBACK_DATA, &PlaybackChannel::null_handler);
}
void PlaybackChannel::handle_start(RedPeer::InMessage* message)
{
PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
SpiceMsgPlaybackStart* start = (SpiceMsgPlaybackStart*)message->data();
handler->set_handler(SPICE_MSG_PLAYBACK_START, NULL);
handler->set_handler(SPICE_MSG_PLAYBACK_STOP, &PlaybackChannel::handle_stop);
#ifdef WAVE_CAPTURE
start_wave();
#endif
if (!_wave_player) {
if (start->format != SPICE_AUDIO_FMT_S16) {
THROW("unexpected format");
}
if (start->channels != 2) {
THROW("unexpected number of channels");
}
int bits_per_sample = 16;
int frame_size = SND_CODEC_MAX_FRAME_SIZE;
if (_mode != SPICE_AUDIO_DATA_MODE_RAW) {
if (snd_codec_create(&_codec, _mode, start->frequency, SND_CODEC_DECODE) != SND_CODEC_OK)
THROW("create decoder");
frame_size = snd_codec_frame_size(_codec);
}
try {
_wave_player = Platform::create_player(start->frequency, bits_per_sample,
start->channels, frame_size);
} catch (...) {
LOG_WARN("create player failed");
//todo: support disconnecting single channel
disable();
return;
}
_frame_bytes = frame_size * start->channels * bits_per_sample / 8;
}
_playing = true;
_frame_count = 0;
set_data_handler();
}
void PlaybackChannel::handle_stop(RedPeer::InMessage* message)
{
PlaybackHandler* handler = static_cast<PlaybackHandler*>(get_message_handler());
handler->set_handler(SPICE_MSG_PLAYBACK_STOP, NULL);
handler->set_handler(SPICE_MSG_PLAYBACK_DATA, NULL);
handler->set_handler(SPICE_MSG_PLAYBACK_START, &PlaybackChannel::handle_start);
#ifdef WAVE_CAPTURE
end_wave();
#endif
_wave_player->stop();
_playing = false;
}
void PlaybackChannel::handle_raw_data(RedPeer::InMessage* message)
{
SpiceMsgPlaybackPacket* packet = (SpiceMsgPlaybackPacket*)message->data();
uint8_t* data = packet->data;
uint32_t size = packet->data_size;
#ifdef WAVE_CAPTURE
put_wave_data(data, size);
return;
#endif
if (size != _frame_bytes) {
//for now throw on unexpected size (based on current server imp).
// will probably be replaced by supporting flexible data size in the player imp
THROW("unexpected frame size");
}
if ((_frame_count++ % 1000) == 0) {
get_client().set_mm_time(packet->time - _wave_player->get_delay_ms());
}
_wave_player->write(data);
}
void PlaybackChannel::handle_compressed_data(RedPeer::InMessage* message)
{
SpiceMsgPlaybackPacket* packet = (SpiceMsgPlaybackPacket*)message->data();
uint8_t* data = packet->data;
uint32_t size = packet->data_size;
int pcm_size = _frame_bytes;
uint8_t pcm[_frame_bytes];
if (snd_codec_decode(_codec, data, size, pcm, &pcm_size) != SND_CODEC_OK)
THROW("decode failed");
#ifdef WAVE_CAPTURE
put_wave_data(pcm, _frame_bytes);
return;
#endif
if ((_frame_count++ % 1000) == 0) {
get_client().set_mm_time(packet->time - _wave_player->get_delay_ms());
}
_wave_player->write((uint8_t *)pcm);
}
class PlaybackFactory: public ChannelFactory {
public:
PlaybackFactory() : ChannelFactory(SPICE_CHANNEL_PLAYBACK) {}
virtual RedChannel* construct(RedClient& client, uint32_t id)
{
return new PlaybackChannel(client, id);
}
};
static PlaybackFactory factory;
ChannelFactory& PlaybackChannel::Factory()
{
return factory;
}

View File

@ -1,406 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#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("unhandled 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->set_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->get_generation() == _events_gen) {
return;
}
_events.pop_front();
lock.unlock();
event->response(_owner);
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;
}
#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);
}
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();
}
}
unsigned 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);
}
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);
timer->calc_next_expiration_time(now);
_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;
on_start_running();
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);
}
unsigned ProcessLoop::get_soonest_timeout()
{
return _timers_queue.get_soonest_timeout();
}
void ProcessLoop::timers_action()
{
_timers_queue.timers_action();
}

View File

@ -1,244 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; 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:
void set_generation(uint32_t gen) { _generation = gen;}
uint32_t get_generation() { return _generation;}
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;}
void calc_next_expiration_time(uint64_t now);
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);
unsigned 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();
/* can be used for handling timers in modal loop state in Windows (mainly,
for updating the screen) */
unsigned 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);}
protected:
class WakeupTrigger: public EventSources::Trigger {
public:
virtual void on_event() {}
};
virtual void on_start_running() {}
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

View File

@ -1,119 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_READ_WRITE_MUTEX
#define _H_READ_WRITE_MUTEX
#include "threads.h"
class ReadWriteMutex {
public:
ReadWriteMutex()
{
_state.read_count = 0;
_state.write = false;
_state.write_waiting = false;
}
virtual ~ReadWriteMutex()
{
}
void read_lock()
{
Lock lock(_state_mutex);
while (_state.write || _state.write_waiting) {
_read_cond.wait(lock);
}
++_state.read_count;
}
bool try_read_lock()
{
Lock lock(_state_mutex);
if (_state.write || _state.write_waiting) {
return false;
} else {
++_state.read_count;
return true;
}
}
void read_unlock()
{
Lock lock(_state_mutex);
--_state.read_count;
if (!_state.read_count) { // last reader
_state.write_waiting = false;
release_waiters();
}
}
void write_lock()
{
Lock lock(_state_mutex);
while (_state.read_count || _state.write) {
_state.write_waiting = true;
_write_cond.wait(lock);
}
_state.write = true;
}
bool try_write_lock()
{
Lock lock(_state_mutex);
if (_state.read_count || _state.write) {
return false;
} else {
_state.write = true;
return true;
}
}
void write_unlock()
{
Lock lock(_state_mutex);
_state.write = false;
_state.write_waiting = false;
release_waiters();
}
private:
void release_waiters()
{
_write_cond.notify_one();
_read_cond.notify_all();
}
private:
struct {
unsigned int read_count;
bool write;
bool write_waiting;
} _state;
Mutex _state_mutex;
Condition _read_cond;
Condition _write_cond;
};
#endif

View File

@ -1,293 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "red_client.h"
#include "audio_channels.h"
#include "audio_devices.h"
#define NUM_SAMPLES_MESSAGES 4
static uint32_t get_mm_time()
{
return uint32_t(Platform::get_monolithic_time() / (1000 * 1000));
}
class RecordSamplesMessage: public RedChannel::OutMessage {
public:
RecordSamplesMessage(RecordChannel& channel);
virtual ~RecordSamplesMessage();
virtual RedPeer::OutMessage& peer_message() { return *_message;}
virtual void release();
private:
RecordChannel& _channel;
RedPeer::OutMessage *_message;
};
RecordSamplesMessage::RecordSamplesMessage(RecordChannel& channel)
: _channel (channel)
, _message (new Message(SPICE_MSGC_RECORD_DATA))
{
}
RecordSamplesMessage::~RecordSamplesMessage()
{
delete _message;
}
void RecordSamplesMessage::release()
{
_channel.release_message(this);
}
class RecordHandler: public MessageHandlerImp<RecordChannel, SPICE_CHANNEL_RECORD> {
public:
RecordHandler(RecordChannel& channel)
: MessageHandlerImp<RecordChannel, SPICE_CHANNEL_RECORD>(channel) {}
};
RecordChannel::RecordChannel(RedClient& client, uint32_t id)
: RedChannel(client, SPICE_CHANNEL_RECORD, id, new RecordHandler(*this))
, _wave_recorder (NULL)
, _mode (SPICE_AUDIO_DATA_MODE_INVALID)
, _codec(NULL)
{
for (int i = 0; i < NUM_SAMPLES_MESSAGES; i++) {
_messages.push_front(new RecordSamplesMessage(*this));
}
RecordHandler* handler = static_cast<RecordHandler*>(get_message_handler());
handler->set_handler(SPICE_MSG_MIGRATE, &RecordChannel::handle_migrate);
handler->set_handler(SPICE_MSG_SET_ACK, &RecordChannel::handle_set_ack);
handler->set_handler(SPICE_MSG_PING, &RecordChannel::handle_ping);
handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &RecordChannel::handle_wait_for_channels);
handler->set_handler(SPICE_MSG_DISCONNECTING, &RecordChannel::handle_disconnect);
handler->set_handler(SPICE_MSG_NOTIFY, &RecordChannel::handle_notify);
handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start);
if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1, SND_CODEC_ANY_FREQUENCY))
set_capability(SPICE_RECORD_CAP_CELT_0_5_1);
if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, SND_CODEC_ANY_FREQUENCY))
set_capability(SPICE_RECORD_CAP_OPUS);
}
RecordChannel::~RecordChannel(void)
{
while (!_messages.empty()) {
RecordSamplesMessage *mes;
mes = *_messages.begin();
_messages.pop_front();
delete mes;
}
clear();
}
bool RecordChannel::abort(void)
{
return (!_wave_recorder || _wave_recorder->abort()) && RedChannel::abort();
}
void RecordChannel::set_desired_mode(int frequency)
{
if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_OPUS, frequency) &&
test_capability(SPICE_RECORD_CAP_OPUS))
_mode = SPICE_AUDIO_DATA_MODE_OPUS;
else if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1, frequency) &&
test_capability(SPICE_RECORD_CAP_CELT_0_5_1))
_mode = SPICE_AUDIO_DATA_MODE_CELT_0_5_1;
else
_mode = SPICE_AUDIO_DATA_MODE_RAW;
}
void RecordChannel::send_record_mode()
{
Message* message = new Message(SPICE_MSGC_RECORD_MODE);
SpiceMsgcRecordMode mode;
mode.time = get_mm_time();
mode.mode = _mode;
_marshallers->msgc_record_mode(message->marshaller(), &mode);
post_message(message);
}
void RecordChannel::on_disconnect()
{
clear();
}
void RecordChannel::send_start_mark()
{
Message* message = new Message(SPICE_MSGC_RECORD_START_MARK);
SpiceMsgcRecordStartMark start_mark;
start_mark.time = get_mm_time();
_marshallers->msgc_record_start_mark(message->marshaller(), &start_mark);
post_message(message);
}
void RecordChannel::handle_start(RedPeer::InMessage* message)
{
RecordHandler* handler = static_cast<RecordHandler*>(get_message_handler());
SpiceMsgRecordStart* start = (SpiceMsgRecordStart*)message->data();
handler->set_handler(SPICE_MSG_RECORD_START, NULL);
handler->set_handler(SPICE_MSG_RECORD_STOP, &RecordChannel::handle_stop);
ASSERT(!_wave_recorder);
// for now support only one setting
if (start->format != SPICE_AUDIO_FMT_S16) {
THROW("unexpected format");
}
if (start->channels != 2) {
THROW("unexpected number of channels");
}
set_desired_mode(start->frequency);
int frame_size = SND_CODEC_MAX_FRAME_SIZE;
if (_mode != SPICE_AUDIO_DATA_MODE_RAW) {
if (snd_codec_create(&_codec, _mode, start->frequency, SND_CODEC_ENCODE) != SND_CODEC_OK)
THROW("create encoder failed");
frame_size = snd_codec_frame_size(_codec);
}
int bits_per_sample = 16;
try {
_wave_recorder = Platform::create_recorder(*this, start->frequency,
bits_per_sample,
start->channels,
frame_size);
} catch (...) {
LOG_WARN("create recorder failed");
return;
}
_frame_bytes = frame_size * bits_per_sample * start->channels / 8;
send_record_mode();
send_start_mark();
_wave_recorder->start();
}
void RecordChannel::clear()
{
if (_wave_recorder) {
_wave_recorder->stop();
delete _wave_recorder;
_wave_recorder = NULL;
}
snd_codec_destroy(&_codec);
}
void RecordChannel::handle_stop(RedPeer::InMessage* message)
{
RecordHandler* handler = static_cast<RecordHandler*>(get_message_handler());
handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start);
handler->set_handler(SPICE_MSG_RECORD_STOP, NULL);
if (!_wave_recorder) {
return;
}
clear();
}
RecordSamplesMessage* RecordChannel::get_message()
{
Lock lock(_messages_lock);
if (_messages.empty()) {
return NULL;
}
RecordSamplesMessage* ret = *_messages.begin();
_messages.pop_front();
return ret;
}
void RecordChannel::release_message(RecordSamplesMessage *message)
{
Lock lock(_messages_lock);
_messages.push_front(message);
}
void RecordChannel::add_event_source(EventSources::File& event_source)
{
get_process_loop().add_file(event_source);
}
void RecordChannel::remove_event_source(EventSources::File& event_source)
{
get_process_loop().remove_file(event_source);
}
void RecordChannel::add_event_source(EventSources::Trigger& event_source)
{
get_process_loop().add_trigger(event_source);
}
void RecordChannel::remove_event_source(EventSources::Trigger& event_source)
{
get_process_loop().remove_trigger(event_source);
}
void RecordChannel::push_frame(uint8_t *frame)
{
RecordSamplesMessage *message;
if (!(message = get_message())) {
DBG(0, "blocked");
return;
}
int n;
if (_mode == SPICE_AUDIO_DATA_MODE_RAW) {
n = _frame_bytes;
} else {
n = sizeof(compressed_buf);
if (snd_codec_encode(_codec, frame, _frame_bytes, compressed_buf, &n) != SND_CODEC_OK)
THROW("encode failed");
frame = compressed_buf;
}
RedPeer::OutMessage& peer_message = message->peer_message();
peer_message.reset(SPICE_MSGC_RECORD_DATA);
SpiceMsgcRecordPacket packet;
packet.time = get_mm_time();
_marshallers->msgc_record_data(peer_message.marshaller(), &packet);
spice_marshaller_add(peer_message.marshaller(), frame, n);
post_message(message);
}
class RecordFactory: public ChannelFactory {
public:
RecordFactory() : ChannelFactory(SPICE_CHANNEL_RECORD) {}
virtual RedChannel* construct(RedClient& client, uint32_t id)
{
return new RecordChannel(client, id);
}
};
static RecordFactory factory;
ChannelFactory& RecordChannel::Factory()
{
return factory;
}

View File

@ -1,26 +0,0 @@
/*
Copyright (C) 2011 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RED_CANVAS_BASE
#define _H_RED_CANVAS_BASE
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "common/canvas_base.h"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#endif

View File

@ -1,887 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "red_channel.h"
#include "red_client.h"
#include "application.h"
#include "debug.h"
#include "utils.h"
#include "openssl/rsa.h"
#include "openssl/evp.h"
#include "openssl/x509.h"
void MigrationDisconnectSrcEvent::response(AbstractProcessLoop& events_loop)
{
static_cast<RedChannel*>(events_loop.get_owner())->do_migration_disconnect_src();
}
void MigrationConnectTargetEvent::response(AbstractProcessLoop& events_loop)
{
static_cast<RedChannel*>(events_loop.get_owner())->do_migration_connect_target();
}
RedChannelBase::RedChannelBase(uint8_t type, uint8_t id, const ChannelCaps& common_caps,
const ChannelCaps& caps)
: RedPeer()
, _type (type)
, _id (id)
, _common_caps (common_caps)
, _caps (caps)
{
}
RedChannelBase::~RedChannelBase()
{
}
static const char *spice_link_error_string(int err)
{
switch (err) {
case SPICE_LINK_ERR_OK: return "no error";
case SPICE_LINK_ERR_ERROR: return "general error";
case SPICE_LINK_ERR_INVALID_MAGIC: return "invalid magic";
case SPICE_LINK_ERR_INVALID_DATA: return "invalid data";
case SPICE_LINK_ERR_VERSION_MISMATCH: return "version mismatch";
case SPICE_LINK_ERR_NEED_SECURED: return "need secured connection";
case SPICE_LINK_ERR_NEED_UNSECURED: return "need unsecured connection";
case SPICE_LINK_ERR_PERMISSION_DENIED: return "permission denied";
case SPICE_LINK_ERR_BAD_CONNECTION_ID: return "bad connection id";
case SPICE_LINK_ERR_CHANNEL_NOT_AVAILABLE: return "channel not available";
}
return "";
}
void RedChannelBase::link(uint32_t connection_id, const std::string& password,
int protocol)
{
SpiceLinkHeader header;
SpiceLinkMess link_mess;
SpiceLinkReply* reply;
uint32_t link_res;
uint32_t i;
BIO *bioKey;
uint8_t *buffer, *p;
uint32_t expected_major;
header.magic = SPICE_MAGIC;
header.size = sizeof(link_mess);
if (protocol == 1) {
/* protocol 1 == major 1, old 0.4 protocol, last active minor */
expected_major = header.major_version = 1;
header.minor_version = 3;
} else if (protocol == 2) {
/* protocol 2 == current */
expected_major = header.major_version = SPICE_VERSION_MAJOR;
header.minor_version = SPICE_VERSION_MINOR;
} else {
THROW("unsupported protocol version specified");
}
link_mess.connection_id = connection_id;
link_mess.channel_type = _type;
link_mess.channel_id = _id;
link_mess.num_common_caps = get_common_caps().size();
link_mess.num_channel_caps = get_caps().size();
link_mess.caps_offset = sizeof(link_mess);
header.size += (link_mess.num_common_caps + link_mess.num_channel_caps) * sizeof(uint32_t);
buffer =
new uint8_t[sizeof(header) + sizeof(link_mess) +
_common_caps.size() * sizeof(uint32_t) +
_caps.size() * sizeof(uint32_t)];
p = buffer;
memcpy(p, (uint8_t*)&header, sizeof(header));
p += sizeof(header);
memcpy(p, (uint8_t*)&link_mess, sizeof(link_mess));
p += sizeof(link_mess);
for (i = 0; i < _common_caps.size(); i++) {
*(uint32_t *)p = _common_caps[i];
p += sizeof(uint32_t);
}
for (i = 0; i < _caps.size(); i++) {
*(uint32_t *)p = _caps[i];
p += sizeof(uint32_t);
}
send(buffer, p - buffer);
delete [] buffer;
receive((uint8_t*)&header, sizeof(header));
if (header.magic != SPICE_MAGIC) {
THROW_ERR(SPICEC_ERROR_CODE_CONNECT_FAILED, "bad magic");
}
if (header.major_version != expected_major) {
THROW_ERR(SPICEC_ERROR_CODE_VERSION_MISMATCH,
"version mismatch: expect %u got %u",
expected_major,
header.major_version);
}
_remote_major = header.major_version;
_remote_minor = header.minor_version;
AutoArray<uint8_t> reply_buf(new uint8_t[header.size]);
receive(reply_buf.get(), header.size);
reply = (SpiceLinkReply *)reply_buf.get();
if (reply->error != SPICE_LINK_ERR_OK) {
THROW_ERR(SPICEC_ERROR_CODE_CONNECT_FAILED, "connect error %u - %s",
reply->error, spice_link_error_string(reply->error));
}
uint32_t num_caps = reply->num_channel_caps + reply->num_common_caps;
if ((uint8_t *)(reply + 1) > reply_buf.get() + header.size ||
(uint8_t *)reply + reply->caps_offset + num_caps * sizeof(uint32_t) >
reply_buf.get() + header.size) {
THROW_ERR(SPICEC_ERROR_CODE_CONNECT_FAILED, "access violation");
}
uint32_t *caps = (uint32_t *)((uint8_t *)reply + reply->caps_offset);
_remote_common_caps.clear();
for (i = 0; i < reply->num_common_caps; i++, caps++) {
_remote_common_caps.resize(i + 1);
_remote_common_caps[i] = *caps;
}
_remote_caps.clear();
for (i = 0; i < reply->num_channel_caps; i++, caps++) {
_remote_caps.resize(i + 1);
_remote_caps[i] = *caps;
}
bioKey = BIO_new(BIO_s_mem());
if (bioKey != NULL) {
EVP_PKEY *pubkey;
int nRSASize;
RSA *rsa;
BIO_write(bioKey, reply->pub_key, SPICE_TICKET_PUBKEY_BYTES);
pubkey = d2i_PUBKEY_bio(bioKey, NULL);
rsa = pubkey->pkey.rsa;
nRSASize = RSA_size(rsa);
AutoArray<unsigned char> bufEncrypted(new unsigned char[nRSASize]);
/*
The use of RSA encryption limit the potential maximum password length.
for RSA_PKCS1_OAEP_PADDING it is RSA_size(rsa) - 41.
*/
if (RSA_public_encrypt(password.length() + 1, (unsigned char *)password.c_str(),
(uint8_t *)bufEncrypted.get(),
rsa, RSA_PKCS1_OAEP_PADDING) > 0) {
send((uint8_t*)bufEncrypted.get(), nRSASize);
} else {
EVP_PKEY_free(pubkey);
BIO_free(bioKey);
THROW("could not encrypt password");
}
memset(bufEncrypted.get(), 0, nRSASize);
EVP_PKEY_free(pubkey);
} else {
THROW("Could not initiate BIO");
}
BIO_free(bioKey);
receive((uint8_t*)&link_res, sizeof(link_res));
if (link_res != SPICE_LINK_ERR_OK) {
int error_code = (link_res == SPICE_LINK_ERR_PERMISSION_DENIED) ?
SPICEC_ERROR_CODE_CONNECT_FAILED : SPICEC_ERROR_CODE_CONNECT_FAILED;
THROW_ERR(error_code, "connect failed %u", link_res);
}
}
void RedChannelBase::connect(const ConnectionOptions& options, uint32_t connection_id,
const char* host, std::string password)
{
int protocol = options.protocol;
if (protocol == 0) { /* AUTO, try major 2 first */
protocol = 2;
}
retry:
try {
if (options.allow_unsecure()) {
try {
RedPeer::connect_unsecure(host, options.unsecure_port);
link(connection_id, password, protocol);
return;
} catch (Exception& e) {
// On protocol version mismatch, don't connect_secure with the same version
if (e.get_error_code() == SPICEC_ERROR_CODE_VERSION_MISMATCH ||
!options.allow_secure()) {
throw;
}
RedPeer::close();
}
}
ASSERT(options.allow_secure());
RedPeer::connect_secure(options, host);
link(connection_id, password, protocol);
} catch (Exception& e) {
// On protocol version mismatch, retry with older version
if (e.get_error_code() == SPICEC_ERROR_CODE_VERSION_MISMATCH &&
protocol == 2 && options.protocol == 0) {
RedPeer::cleanup();
protocol = 1;
goto retry;
}
throw;
}
}
void RedChannelBase::set_capability(ChannelCaps& caps, uint32_t cap)
{
uint32_t word_index = cap / 32;
if (caps.size() < word_index + 1) {
caps.resize(word_index + 1);
}
caps[word_index] |= 1 << (cap % 32);
}
void RedChannelBase::set_common_capability(uint32_t cap)
{
set_capability(_common_caps, cap);
}
void RedChannelBase::set_capability(uint32_t cap)
{
set_capability(_caps, cap);
}
bool RedChannelBase::test_capability(const ChannelCaps& caps, uint32_t cap)
{
uint32_t word_index = cap / 32;
if (caps.size() < word_index + 1) {
return false;
}
return (caps[word_index] & (1 << (cap % 32))) != 0;
}
bool RedChannelBase::test_common_capability(uint32_t cap)
{
return test_capability(_remote_common_caps, cap);
}
bool RedChannelBase::test_capability(uint32_t cap)
{
return test_capability(_remote_caps, cap);
}
void RedChannelBase::swap(RedChannelBase* other)
{
int tmp_ver;
RedPeer::swap(other);
tmp_ver = _remote_major;
_remote_major = other->_remote_major;
other->_remote_major = tmp_ver;
tmp_ver = _remote_minor;
_remote_minor = other->_remote_minor;
other->_remote_minor = tmp_ver;
}
SendTrigger::SendTrigger(RedChannel& channel)
: _channel (channel)
{
}
void SendTrigger::on_event()
{
_channel.on_send_trigger();
}
SPICE_GNUC_NORETURN void AbortTrigger::on_event()
{
THROW("abort");
}
RedChannel::RedChannel(RedClient& client, uint8_t type, uint8_t id,
RedChannel::MessageHandler* handler,
Platform::ThreadPriority worker_priority)
: RedChannelBase(type, id, ChannelCaps(), ChannelCaps())
, _marshallers (NULL)
, _client (client)
, _state (PASSIVE_STATE)
, _action (WAIT_ACTION)
, _error (SPICEC_ERROR_CODE_SUCCESS)
, _wait_for_threads (true)
, _socket_in_loop (false)
, _worker (NULL)
, _worker_priority (worker_priority)
, _message_handler (handler)
, _outgoing_message (NULL)
, _incomming_header_pos (0)
, _incomming_message (NULL)
, _message_ack_count (0)
, _message_ack_window (0)
, _loop (this)
, _send_trigger (*this)
, _disconnect_stamp (0)
, _disconnect_reason (SPICE_LINK_ERR_OK)
{
_loop.add_trigger(_send_trigger);
_loop.add_trigger(_abort_trigger);
}
RedChannel::~RedChannel()
{
ASSERT(_state == TERMINATED_STATE || _state == PASSIVE_STATE);
delete _worker;
}
void* RedChannel::worker_main(void *data)
{
try {
RedChannel* channel = static_cast<RedChannel*>(data);
channel->set_state(DISCONNECTED_STATE);
Platform::set_thread_priority(NULL, channel->get_worker_priority());
channel->run();
} catch (Exception& e) {
LOG_ERROR("unhandled exception: %s", e.what());
} catch (std::exception& e) {
LOG_ERROR("unhandled exception: %s", e.what());
} catch (...) {
LOG_ERROR("unhandled exception");
}
return NULL;
}
void RedChannel::post_message(RedChannel::OutMessage* message)
{
Lock lock(_outgoing_lock);
_outgoing_messages.push_back(message);
lock.unlock();
_send_trigger.trigger();
}
RedPeer::CompoundInMessage *RedChannel::receive()
{
CompoundInMessage *message = RedChannelBase::receive();
on_message_received();
return message;
}
RedChannel::OutMessage* RedChannel::get_outgoing_message()
{
if (_state != CONNECTED_STATE || _outgoing_messages.empty()) {
return NULL;
}
RedChannel::OutMessage* message = _outgoing_messages.front();
_outgoing_messages.pop_front();
return message;
}
class AutoMessage {
public:
AutoMessage(RedChannel::OutMessage* message) : _message (message) {}
~AutoMessage() {if (_message) _message->release();}
void set(RedChannel::OutMessage* message) { _message = message;}
RedChannel::OutMessage* get() { return _message;}
RedChannel::OutMessage* release();
private:
RedChannel::OutMessage* _message;
};
RedChannel::OutMessage* AutoMessage::release()
{
RedChannel::OutMessage* ret = _message;
_message = NULL;
return ret;
}
void RedChannel::start()
{
ASSERT(!_worker);
_worker = new Thread(RedChannel::worker_main, this);
Lock lock(_state_lock);
while (_state == PASSIVE_STATE) {
_state_cond.wait(lock);
}
}
void RedChannel::set_state(int state)
{
Lock lock(_state_lock);
_state = state;
_state_cond.notify_all();
}
void RedChannel::connect()
{
Lock lock(_action_lock);
if (_state != DISCONNECTED_STATE && _state != PASSIVE_STATE) {
return;
}
_action = CONNECT_ACTION;
_action_cond.notify_one();
}
void RedChannel::disconnect()
{
clear_outgoing_messages();
Lock lock(_action_lock);
if (_state != CONNECTING_STATE && _state != CONNECTED_STATE) {
return;
}
_action = DISCONNECT_ACTION;
RedPeer::disconnect();
_action_cond.notify_one();
}
void RedChannel::disconnect_migration_src()
{
clear_outgoing_messages();
Lock lock(_action_lock);
if (_state == CONNECTING_STATE || _state == CONNECTED_STATE) {
AutoRef<MigrationDisconnectSrcEvent> migrate_event(new MigrationDisconnectSrcEvent());
_loop.push_event(*migrate_event);
}
}
void RedChannel::connect_migration_target()
{
LOG_INFO("");
AutoRef<MigrationConnectTargetEvent> migrate_event(new MigrationConnectTargetEvent());
_loop.push_event(*migrate_event);
}
void RedChannel::do_migration_disconnect_src()
{
if (_socket_in_loop) {
_socket_in_loop = false;
_loop.remove_socket(*this);
}
clear_outgoing_messages();
if (_outgoing_message) {
_outgoing_message->release();
_outgoing_message = NULL;
}
_incomming_header_pos = 0;
if (_incomming_message) {
_incomming_message->unref();
_incomming_message = NULL;
}
on_disconnect_mig_src();
get_client().migrate_channel(*this);
get_client().on_channel_disconnect_mig_src_completed(*this);
}
void RedChannel::do_migration_connect_target()
{
LOG_INFO("");
ASSERT(get_client().get_protocol() != 0);
if (get_client().get_protocol() == 1) {
_marshallers = spice_message_marshallers_get1();
} else {
_marshallers = spice_message_marshallers_get();
}
_loop.add_socket(*this);
_socket_in_loop = true;
on_connect_mig_target();
set_state(CONNECTED_STATE);
on_event();
}
void RedChannel::clear_outgoing_messages()
{
Lock lock(_outgoing_lock);
while (!_outgoing_messages.empty()) {
RedChannel::OutMessage* message = _outgoing_messages.front();
_outgoing_messages.pop_front();
message->release();
}
}
void RedChannel::run()
{
for (;;) {
Lock lock(_action_lock);
if (_action == WAIT_ACTION) {
_action_cond.wait(lock);
}
int action = _action;
_action = WAIT_ACTION;
lock.unlock();
switch (action) {
case CONNECT_ACTION:
try {
get_client().get_sync_info(get_type(), get_id(), _sync_info);
on_connecting();
set_state(CONNECTING_STATE);
ConnectionOptions con_options(_client.get_connection_options(get_type()),
_client.get_port(),
_client.get_sport(),
_client.get_protocol(),
_client.get_host_auth_options(),
_client.get_connection_ciphers());
RedChannelBase::connect(con_options, _client.get_connection_id(),
_client.get_host().c_str(),
_client.get_password().c_str());
/* If automatic protocol, remember the first connect protocol type */
if (_client.get_protocol() == 0) {
if (get_peer_major() == 1) {
_client.set_protocol(1);
} else {
/* Major is 2 or unstable high value, use 2 */
_client.set_protocol(2);
}
}
/* Initialize when we know the remote major version */
if (_client.get_peer_major() == 1) {
_marshallers = spice_message_marshallers_get1();
} else {
_marshallers = spice_message_marshallers_get();
}
on_connect();
set_state(CONNECTED_STATE);
_loop.add_socket(*this);
_socket_in_loop = true;
on_event();
_loop.run();
} catch (RedPeer::DisconnectedException&) {
_error = SPICEC_ERROR_CODE_SUCCESS;
} catch (Exception& e) {
LOG_WARN("%s", e.what());
_error = e.get_error_code();
} catch (std::exception& e) {
LOG_WARN("%s", e.what());
_error = SPICEC_ERROR_CODE_ERROR;
}
if (_socket_in_loop) {
_socket_in_loop = false;
_loop.remove_socket(*this);
}
if (_outgoing_message) {
_outgoing_message->release();
_outgoing_message = NULL;
}
_incomming_header_pos = 0;
if (_incomming_message) {
_incomming_message->unref();
_incomming_message = NULL;
}
case DISCONNECT_ACTION:
close();
on_disconnect();
set_state(DISCONNECTED_STATE);
_client.on_channel_disconnected(*this);
continue;
case QUIT_ACTION:
set_state(TERMINATED_STATE);
return;
}
}
}
bool RedChannel::abort()
{
clear_outgoing_messages();
Lock lock(_action_lock);
if (_state == TERMINATED_STATE) {
if (_wait_for_threads) {
_wait_for_threads = false;
_worker->join();
}
return true;
}
_action = QUIT_ACTION;
_action_cond.notify_one();
lock.unlock();
RedPeer::disconnect();
_abort_trigger.trigger();
for (;;) {
Lock state_lock(_state_lock);
if (_state == TERMINATED_STATE) {
break;
}
uint64_t timout = 1000 * 1000 * 100; // 100ms
if (!_state_cond.timed_wait(state_lock, timout)) {
return false;
}
}
if (_wait_for_threads) {
_wait_for_threads = false;
_worker->join();
}
return true;
}
void RedChannel::send_messages()
{
if (_outgoing_message) {
return;
}
for (;;) {
Lock lock(_outgoing_lock);
AutoMessage message(get_outgoing_message());
if (!message.get()) {
return;
}
RedPeer::OutMessage& peer_message = message.get()->peer_message();
uint32_t n = send(peer_message);
if (n != peer_message.message_size()) {
_outgoing_message = message.release();
_outgoing_pos = n;
return;
}
}
}
void RedChannel::on_send_trigger()
{
send_messages();
}
void RedChannel::on_message_received()
{
if (_message_ack_count && !--_message_ack_count) {
post_message(new Message(SPICE_MSGC_ACK));
_message_ack_count = _message_ack_window;
}
}
void RedChannel::on_message_complition(uint64_t serial)
{
Lock lock(*_sync_info.lock);
*_sync_info.message_serial = serial;
_sync_info.condition->notify_all();
}
void RedChannel::receive_messages()
{
for (;;) {
uint32_t n = RedPeer::receive((uint8_t*)&_incomming_header, sizeof(SpiceDataHeader));
if (n != sizeof(SpiceDataHeader)) {
_incomming_header_pos = n;
return;
}
AutoRef<CompoundInMessage> message(new CompoundInMessage(_incomming_header.serial,
_incomming_header.type,
_incomming_header.size,
_incomming_header.sub_list));
n = RedPeer::receive((*message)->data(), (*message)->compound_size());
if (n != (*message)->compound_size()) {
_incomming_message = message.release();
_incomming_message_pos = n;
return;
}
on_message_received();
_message_handler->handle_message(*(*message));
on_message_complition((*message)->serial());
}
}
void RedChannel::on_event()
{
if (_outgoing_message) {
RedPeer::OutMessage& peer_message = _outgoing_message->peer_message();
_outgoing_pos += do_send(peer_message, _outgoing_pos);
if (_outgoing_pos == peer_message.message_size()) {
_outgoing_message->release();
_outgoing_message = NULL;
}
}
send_messages();
if (_incomming_header_pos) {
_incomming_header_pos += RedPeer::receive(((uint8_t*)&_incomming_header) +
_incomming_header_pos,
sizeof(SpiceDataHeader) - _incomming_header_pos);
if (_incomming_header_pos != sizeof(SpiceDataHeader)) {
return;
}
_incomming_header_pos = 0;
_incomming_message = new CompoundInMessage(_incomming_header.serial,
_incomming_header.type,
_incomming_header.size,
_incomming_header.sub_list);
_incomming_message_pos = 0;
}
if (_incomming_message) {
_incomming_message_pos += RedPeer::receive(_incomming_message->data() +
_incomming_message_pos,
_incomming_message->compound_size() -
_incomming_message_pos);
if (_incomming_message_pos != _incomming_message->compound_size()) {
return;
}
AutoRef<CompoundInMessage> message(_incomming_message);
_incomming_message = NULL;
on_message_received();
_message_handler->handle_message(*(*message));
on_message_complition((*message)->serial());
}
receive_messages();
}
void RedChannel::send_migrate_flush_mark()
{
if (_outgoing_message) {
RedPeer::OutMessage& peer_message = _outgoing_message->peer_message();
do_send(peer_message, _outgoing_pos);
_outgoing_message->release();
_outgoing_message = NULL;
}
Lock lock(_outgoing_lock);
for (;;) {
AutoMessage message(get_outgoing_message());
if (!message.get()) {
break;
}
send(message.get()->peer_message());
}
lock.unlock();
std::auto_ptr<RedPeer::OutMessage> message(new RedPeer::OutMessage(SPICE_MSGC_MIGRATE_FLUSH_MARK));
send(*message);
}
void RedChannel::handle_migrate(RedPeer::InMessage* message)
{
DBG(0, "channel type %u id %u", get_type(), get_id());
_socket_in_loop = false;
_loop.remove_socket(*this);
SpiceMsgMigrate* migrate = (SpiceMsgMigrate*)message->data();
if (migrate->flags & SPICE_MIGRATE_NEED_FLUSH) {
send_migrate_flush_mark();
}
AutoRef<CompoundInMessage> data_message;
if (migrate->flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
data_message.reset(receive());
}
_client.migrate_channel(*this);
if (migrate->flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
if ((*data_message)->type() != SPICE_MSG_MIGRATE_DATA) {
THROW("expect SPICE_MSG_MIGRATE_DATA");
}
std::auto_ptr<RedPeer::OutMessage> message(new RedPeer::OutMessage(SPICE_MSGC_MIGRATE_DATA));
spice_marshaller_add(message->marshaller(), (*data_message)->data(), (*data_message)->size());
send(*message);
}
_loop.add_socket(*this);
_socket_in_loop = true;
on_migrate();
set_state(CONNECTED_STATE);
on_event();
}
void RedChannel::handle_set_ack(RedPeer::InMessage* message)
{
SpiceMsgSetAck* ack = (SpiceMsgSetAck*)message->data();
_message_ack_window = _message_ack_count = ack->window;
Message *response = new Message(SPICE_MSGC_ACK_SYNC);
SpiceMsgcAckSync sync;
sync.generation = ack->generation;
_marshallers->msgc_ack_sync(response->marshaller(), &sync);
post_message(response);
}
void RedChannel::handle_ping(RedPeer::InMessage* message)
{
SpiceMsgPing *ping = (SpiceMsgPing *)message->data();
Message *pong = new Message(SPICE_MSGC_PONG);
_marshallers->msgc_pong(pong->marshaller(), ping);
post_message(pong);
}
void RedChannel::handle_disconnect(RedPeer::InMessage* message)
{
SpiceMsgDisconnect *disconnect = (SpiceMsgDisconnect *)message->data();
_disconnect_stamp = disconnect->time_stamp;
_disconnect_reason = disconnect->reason;
}
void RedChannel::handle_notify(RedPeer::InMessage* message)
{
SpiceMsgNotify *notify = (SpiceMsgNotify *)message->data();
const char *severity;
const char *visibility;
char *message_str = (char *)"";
const char *message_prefix = "";
static const char* severity_strings[] = {"info", "warn", "error"};
static const char* visibility_strings[] = {"!", "!!", "!!!"};
if (notify->severity > SPICE_NOTIFY_SEVERITY_ERROR) {
THROW("bad severity");
}
severity = severity_strings[notify->severity];
if (notify->visibilty > SPICE_NOTIFY_VISIBILITY_HIGH) {
THROW("bad visibility");
}
visibility = visibility_strings[notify->visibilty];
if (notify->message_len) {
if ((message->size() - sizeof(*notify) < notify->message_len)) {
THROW("access violation");
}
message_str = new char[notify->message_len + 1];
memcpy(message_str, notify->message, notify->message_len);
message_str[notify->message_len] = 0;
message_prefix = ": ";
}
LOG_INFO("remote channel %u:%u %s%s #%u%s%s",
get_type(), get_id(),
severity, visibility,
notify->what,
message_prefix, message_str);
if (notify->message_len) {
delete [] message_str;
}
}
void RedChannel::handle_wait_for_channels(RedPeer::InMessage* message)
{
SpiceMsgWaitForChannels *wait = (SpiceMsgWaitForChannels *)message->data();
if (message->size() < sizeof(*wait) + wait->wait_count * sizeof(wait->wait_list[0])) {
THROW("access violation");
}
_client.wait_for_channels(wait->wait_count, wait->wait_list);
}

View File

@ -1,353 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_REDCHANNEL
#define _H_REDCHANNEL
#include "common/client_demarshallers.h"
#include "common/client_marshallers.h"
#include "common.h"
#include "utils.h"
#include "threads.h"
#include "red_peer.h"
#include "platform.h"
#include "process_loop.h"
enum {
PASSIVE_STATE,
DISCONNECTED_STATE,
CONNECTING_STATE,
CONNECTED_STATE,
TERMINATED_STATE,
};
enum {
WAIT_ACTION,
CONNECT_ACTION,
DISCONNECT_ACTION,
QUIT_ACTION,
};
class RedClient;
class RedChannel;
typedef std::vector<uint32_t> ChannelCaps;
class RedChannelBase: public RedPeer {
public:
RedChannelBase(uint8_t type, uint8_t id, const ChannelCaps& common_caps,
const ChannelCaps& caps);
virtual ~RedChannelBase();
uint8_t get_type() { return _type;}
uint8_t get_id() { return _id;}
void connect(const ConnectionOptions& options, uint32_t connection_id, const char *host,
std::string password);
const ChannelCaps& get_common_caps() { return _common_caps;}
const ChannelCaps& get_caps() {return _caps;}
uint32_t get_peer_major() { return _remote_major;}
uint32_t get_peer_minor() { return _remote_minor;}
virtual void swap(RedChannelBase* other);
protected:
void set_common_capability(uint32_t cap);
void set_capability(uint32_t cap);
bool test_common_capability(uint32_t cap);
bool test_capability(uint32_t cap);
private:
void set_capability(ChannelCaps& caps, uint32_t cap);
bool test_capability(const ChannelCaps& caps, uint32_t cap);
void link(uint32_t connection_id, const std::string& password, int protocol);
private:
uint8_t _type;
uint8_t _id;
ChannelCaps _common_caps;
ChannelCaps _caps;
ChannelCaps _remote_common_caps;
ChannelCaps _remote_caps;
uint32_t _remote_major;
uint32_t _remote_minor;
};
class SendTrigger: public EventSources::Trigger {
public:
SendTrigger(RedChannel& channel);
virtual void on_event();
private:
RedChannel& _channel;
};
class AbortTrigger: public EventSources::Trigger {
public:
virtual void on_event();
};
class MigrationDisconnectSrcEvent: public Event {
public:
virtual void response(AbstractProcessLoop& events_loop);
};
class MigrationConnectTargetEvent: public Event {
public:
virtual void response(AbstractProcessLoop& events_loop);
};
struct SyncInfo {
Mutex* lock;
Condition* condition;
uint64_t* message_serial;
};
class RedChannel: public RedChannelBase {
public:
class MessageHandler;
class OutMessage;
RedChannel(RedClient& client, uint8_t type, uint8_t id, MessageHandler* handler,
Platform::ThreadPriority worker_priority = Platform::PRIORITY_NORMAL);
virtual ~RedChannel();
void start();
virtual void connect();
virtual void disconnect();
virtual bool abort();
virtual void disconnect_migration_src();
virtual void connect_migration_target();
virtual CompoundInMessage *receive();
virtual void post_message(RedChannel::OutMessage* message);
int get_connection_error() { return _error;}
Platform::ThreadPriority get_worker_priority() { return _worker_priority;}
protected:
RedClient& get_client() { return _client;}
ProcessLoop& get_process_loop() { return _loop;}
MessageHandler* get_message_handler() { return _message_handler.get();}
virtual void on_connecting() {}
virtual void on_connect() {}
virtual void on_disconnect() {}
virtual void on_migrate() {}
virtual void on_disconnect_mig_src() { on_disconnect();}
virtual void on_connect_mig_target() { on_connect();}
void handle_migrate(RedPeer::InMessage* message);
void handle_set_ack(RedPeer::InMessage* message);
void handle_ping(RedPeer::InMessage* message);
void handle_wait_for_channels(RedPeer::InMessage* message);
void handle_disconnect(RedPeer::InMessage* message);
void handle_notify(RedPeer::InMessage* message);
SpiceMessageMarshallers *_marshallers;
private:
void set_state(int state);
void run();
void send_migrate_flush_mark();
void send_messages();
void receive_messages();
void on_send_trigger();
virtual void on_event();
void on_message_received();
void on_message_complition(uint64_t serial);
void do_migration_disconnect_src();
void do_migration_connect_target();
static void* worker_main(void *);
RedChannel::OutMessage* get_outgoing_message();
void clear_outgoing_messages();
private:
RedClient& _client;
int _state;
int _action;
int _error;
bool _wait_for_threads;
bool _socket_in_loop;
Thread* _worker;
Platform::ThreadPriority _worker_priority;
std::auto_ptr<MessageHandler> _message_handler;
Mutex _state_lock;
Condition _state_cond;
Mutex _action_lock;
Condition _action_cond;
SyncInfo _sync_info;
Mutex _outgoing_lock;
std::list<RedChannel::OutMessage*> _outgoing_messages;
RedChannel::OutMessage* _outgoing_message;
uint32_t _outgoing_pos;
SpiceDataHeader _incomming_header;
uint32_t _incomming_header_pos;
RedPeer::CompoundInMessage* _incomming_message;
uint32_t _incomming_message_pos;
uint32_t _message_ack_count;
uint32_t _message_ack_window;
ProcessLoop _loop;
SendTrigger _send_trigger;
AbortTrigger _abort_trigger;
uint64_t _disconnect_stamp;
uint64_t _disconnect_reason;
friend class SendTrigger;
friend class MigrationDisconnectSrcEvent;
friend class MigrationConnectTargetEvent;
};
class RedChannel::OutMessage {
public:
OutMessage() {}
virtual ~OutMessage() {}
virtual RedPeer::OutMessage& peer_message() = 0;
virtual void release() = 0;
};
class Message: public RedChannel::OutMessage, public RedPeer::OutMessage {
public:
Message(uint32_t type)
: RedChannel::OutMessage()
, RedPeer::OutMessage(type)
{
}
virtual RedPeer::OutMessage& peer_message() { return *this;}
virtual void release() {delete this;}
};
class RedChannel::MessageHandler {
public:
MessageHandler() {}
virtual ~MessageHandler() {}
virtual void handle_message(RedPeer::CompoundInMessage& message) = 0;
};
template <class HandlerClass, unsigned int channel_id>
class MessageHandlerImp: public RedChannel::MessageHandler {
public:
MessageHandlerImp(HandlerClass& obj);
~MessageHandlerImp() { delete [] _handlers; };
virtual void handle_message(RedPeer::CompoundInMessage& message);
typedef void (HandlerClass::*Handler)(RedPeer::InMessage* message);
void set_handler(unsigned int id, Handler handler);
private:
HandlerClass& _obj;
unsigned int _max_messages;
spice_parse_channel_func_t _parser;
Handler *_handlers;
};
template <class HandlerClass, unsigned int channel_id>
MessageHandlerImp<HandlerClass, channel_id>::MessageHandlerImp(HandlerClass& obj)
: _obj (obj)
, _parser (NULL)
{
/* max_messages is always from current as its larger than for backwards compat */
spice_get_server_channel_parser(channel_id, &_max_messages);
_handlers = new Handler[_max_messages + 1];
memset(_handlers, 0, sizeof(Handler) * (_max_messages + 1));
}
template <class HandlerClass, unsigned int channel_id>
void MessageHandlerImp<HandlerClass, channel_id>::handle_message(RedPeer::CompoundInMessage&
message)
{
uint8_t *msg;
uint8_t *parsed;
uint16_t type;
uint32_t size;
size_t parsed_size;
message_destructor_t parsed_free;
if (_parser == NULL) {
/* We need to do this lazily rather than at constuction because we
don't know the major until we've connected */
if (_obj.get_peer_major() == 1) {
_parser = spice_get_server_channel_parser1(channel_id, NULL);
} else {
_parser = spice_get_server_channel_parser(channel_id, NULL);
}
}
if (message.sub_list()) {
SpiceSubMessageList *sub_list;
sub_list = (SpiceSubMessageList *)(message.data() + message.sub_list());
for (int i = 0; i < sub_list->size; i++) {
SpiceSubMessage *sub = (SpiceSubMessage *)(message.data() + sub_list->sub_messages[i]);
msg = (uint8_t *)(sub + 1);
type = sub->type;
size = sub->size;
parsed = _parser(msg, msg + size, type, _obj.get_peer_minor(), &parsed_size, &parsed_free);
if (parsed == NULL) {
THROW("failed to parse message type %d", type);
}
RedPeer::InMessage sub_message(type, parsed_size, parsed);
(_obj.*_handlers[type])(&sub_message);
parsed_free(parsed);
}
}
msg = message.data();
type = message.type();
size = message.size();
parsed = _parser(msg, msg + size, type, _obj.get_peer_minor(), &parsed_size, &parsed_free);
if (parsed == NULL) {
THROW("failed to parse message channel %d type %d", channel_id, type);
}
RedPeer::InMessage main_message(type, parsed_size, parsed);
(_obj.*_handlers[type])(&main_message);
parsed_free(parsed);
}
template <class HandlerClass, unsigned int channel_id>
void MessageHandlerImp<HandlerClass, channel_id>::set_handler(unsigned int id, Handler handler)
{
if (id > _max_messages) {
THROW("bad handler id");
}
_handlers[id] = handler;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,387 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_REDCLIENT
#define _H_REDCLIENT
#include <list>
#include "common/messages.h"
#include "common.h"
#include "red_peer.h"
#include "red_channel.h"
#include "display_channel.h"
#include "inputs_channel.h"
#include "cursor_channel.h"
#include "audio_channels.h"
#include <spice/vd_agent.h>
#include "process_loop.h"
class Application;
class MigChannel: public RedChannelBase {
public:
MigChannel(uint32_t type, uint32_t id, const ChannelCaps& common_caps, const ChannelCaps& caps)
: RedChannelBase(type, id, common_caps, caps)
, _valid(false) {}
bool is_valid() { return _valid;}
void set_valid(bool val) { _valid = val;}
private:
bool _valid;
};
class Migrate {
public:
Migrate(RedClient& client);
~Migrate();
void start(const SpiceMsgMainMigrationBegin* migrate);
bool abort();
void add_channel(MigChannel* channel);
void clear_channels();
void swap_peer(RedChannelBase& other);
private:
void connect_one(MigChannel& channel, const RedPeer::ConnectionOptions& options,
uint32_t connection_id);
void disconnect_channels();
void close_channels();
void delete_channels();
void run();
static void* worker_main(void *data);
private:
RedClient& _client;
typedef std::list<MigChannel*> MigChannels;
MigChannels _channels;
bool _running;
bool _aborting;
bool _connected;
std::string _password;
std::string _host;
int _port;
int _sport;
RedPeer::HostAuthOptions _auth_options;
std::string _con_ciphers;
Thread* _thread;
Mutex _lock;
Condition _cond;
int _pending_con;
int _protocol;
};
class ChannelFactory {
public:
ChannelFactory(uint32_t type) : _type (type) {}
virtual ~ChannelFactory() {}
uint32_t type() { return _type;}
virtual RedChannel* construct(RedClient& client, uint32_t id) = 0;
private:
uint32_t _type;
};
class GlzDecoderWindowDebug: public GlzDecoderDebug {
public:
virtual SPICE_GNUC_NORETURN void error(const std::string& str)
{
throw Exception(str);
}
virtual void warn(const std::string& str)
{
LOG_WARN("%s", str.c_str());
}
virtual void info(const std::string& str)
{
LOG_INFO("%s", str.c_str());
}
};
class RedClient;
class AgentTimer: public Timer {
public:
virtual void response(AbstractProcessLoop& events_loop);
AgentTimer(RedClient *client) : _client(client) {};
private:
RedClient *_client;
};
typedef std::map< int, RedPeer::ConnectionOptions::Type> PeerConnectionOptMap;
class ForEachChannelFunc {
public:
virtual bool operator() (RedChannel& channel) = 0;
};
class DisplaySetting {
public:
DisplaySetting() : _disable_wallpaper (false)
, _disable_font_smooth (false)
, _disable_animation (false)
, _set_color_depth (false)
{}
bool is_empty() {return !(_disable_wallpaper || _disable_font_smooth ||
_disable_animation || _set_color_depth);}
public:
bool _disable_wallpaper;
bool _disable_font_smooth;
bool _disable_animation;
bool _set_color_depth;
uint32_t _color_depth;
};
class ClipboardGrabEvent : public Event {
public:
ClipboardGrabEvent(uint32_t *types, uint32_t type_count)
{
_types = new uint32_t [type_count];
memcpy(_types, types, type_count * sizeof(uint32_t));
_type_count = type_count;
}
~ClipboardGrabEvent()
{
delete[] _types;
}
virtual void response(AbstractProcessLoop& events_loop);
private:
uint32_t *_types;
uint32_t _type_count;
};
class ClipboardRequestEvent : public Event {
public:
ClipboardRequestEvent(uint32_t type) : _type (type) {}
virtual void response(AbstractProcessLoop& events_loop);
private:
uint32_t _type;
};
class ClipboardNotifyEvent : public Event {
public:
ClipboardNotifyEvent(uint32_t type, uint8_t *data, uint32_t size)
{
_type = type;
_data = new uint8_t [size];
memcpy(_data, data, size);
_size = size;
}
~ClipboardNotifyEvent()
{
delete[] _data;
}
virtual void response(AbstractProcessLoop& events_loop);
private:
uint32_t _type;
uint8_t *_data;
uint32_t _size;
};
class ClipboardReleaseEvent : public Event {
public:
ClipboardReleaseEvent() {}
virtual void response(AbstractProcessLoop& events_loop);
};
class MigrateEndEvent: public Event {
public:
virtual void response(AbstractProcessLoop& events_loop);
};
class RedClient: public RedChannel,
public Platform::ClipboardListener {
public:
friend class RedChannel;
friend class Migrate;
friend class ClipboardGrabEvent;
friend class ClipboardRequestEvent;
friend class ClipboardNotifyEvent;
friend class ClipboardReleaseEvent;
friend class MigrateEndEvent;
RedClient(Application& application);
~RedClient();
void register_channel_factory(ChannelFactory& factory);
virtual void connect();
virtual void disconnect();
virtual bool abort();
void connect(bool wait_main_disconnect);
void push_event(Event* event);
void activate_interval_timer(Timer* timer, unsigned int millisec);
void deactivate_interval_timer(Timer* timer);
void set_target(const std::string& host, int port, int sport, int protocol = 0);
void set_password(const std::string& password) { _password = password;}
void set_auto_display_res(bool auto_display_res) { _auto_display_res = auto_display_res;}
void set_display_setting(DisplaySetting& setting) { _display_setting = setting;}
const std::string& get_password() { return _password;}
const std::string& get_host() { return _host;}
int get_port() { return _port;}
int get_sport() { return _sport;}
int get_protocol() { return _protocol;}
void set_protocol(int protocol) { _protocol = protocol;}
virtual uint32_t get_connection_id() { return _connection_id;}
uint32_t get_mouse_mode() { return _mouse_mode;}
Application& get_application() { return _application;}
bool is_auto_display_res() { return _auto_display_res;}
RedPeer::ConnectionOptions::Type get_connection_options(uint32_t channel_type);
RedPeer::HostAuthOptions& get_host_auth_options() { return _host_auth_opt;}
const std::string& get_connection_ciphers() { return _con_ciphers;}
void get_sync_info(uint8_t channel_type, uint8_t channel_id, SyncInfo& info);
void wait_for_channels(int wait_list_size, SpiceWaitForChannel* wait_list);
PixmapCache& get_pixmap_cache() {return _pixmap_cache;}
uint64_t get_pixmap_cache_size() { return _pixmap_cache_size;}
void on_display_mode_change();
void on_clipboard_grab(uint32_t *types, uint32_t type_count);
void on_clipboard_request(uint32_t type);
void on_clipboard_notify(uint32_t type, uint8_t* data, int32_t size);
void on_clipboard_release();
void for_each_channel(ForEachChannelFunc& func);
void on_mouse_capture_trigger(RedScreen& screen);
GlzDecoderWindow& get_glz_window() {return _glz_window;}
int get_glz_window_size() { return _glz_window_size;}
void set_mm_time(uint32_t time);
uint32_t get_mm_time();
void send_main_attach_channels(void);
protected:
virtual void on_connecting();
virtual void on_connect();
virtual void on_disconnect();
virtual void on_connect_mig_target() {}
virtual void on_disconnect_mig_src();
private:
void on_channel_disconnected(RedChannel& channel);
void on_channel_disconnect_mig_src_completed(RedChannel& channel);
void send_migrate_end();
void migrate_channel(RedChannel& channel);
void send_agent_announce_capabilities(bool request);
void send_agent_monitors_config();
void send_agent_display_config();
void calc_pixmap_cach_and_glz_window_size(uint32_t display_channels_hint,
uint32_t pci_mem_hint);
void set_mouse_mode(uint32_t supported_modes, uint32_t current_mode);
void handle_migrate_begin(RedPeer::InMessage* message);
void handle_migrate_cancel(RedPeer::InMessage* message);
void handle_migrate_end(RedPeer::InMessage* message);
void handle_init(RedPeer::InMessage* message);
void handle_channels(RedPeer::InMessage* message);
void handle_mouse_mode(RedPeer::InMessage* message);
void handle_mm_time(RedPeer::InMessage* message);
void handle_agent_connected(RedPeer::InMessage* message);
void handle_agent_disconnected(RedPeer::InMessage* message);
void handle_agent_data(RedPeer::InMessage* message);
void handle_agent_tokens(RedPeer::InMessage* message);
void handle_migrate_switch_host(RedPeer::InMessage* message);
void dispatch_agent_message(VDAgentMessage* msg, void* data);
bool init_guest_display();
void on_agent_reply(VDAgentReply* reply);
void on_agent_announce_capabilities(VDAgentAnnounceCapabilities* caps,
uint32_t msg_size);
void do_send_agent_clipboard();
void send_agent_clipboard_message(uint32_t message_type, uint32_t size = 0, void* data = NULL);
void send_agent_clipboard_notify_message(uint32_t type, uint8_t *data, uint32_t size);
ChannelFactory* find_factory(uint32_t type);
void create_channel(uint32_t type, uint32_t id);
void disconnect_channels();
void delete_channels();
bool abort_channels();
private:
Application& _application;
std::string _host;
int _port;
int _sport;
int _protocol;
std::string _password;
uint32_t _connection_id;
uint32_t _mouse_mode;
Mutex _notify_lock;
bool _notify_disconnect;
bool _auto_display_res;
DisplaySetting _display_setting;
uint32_t _agent_reply_wait_type;
bool _aborting;
bool _msg_attach_channels_sent;
bool _agent_connected;
bool _agent_mon_config_sent;
bool _agent_disp_config_sent;
//FIXME: rename to in/out, extract all agent stuff?
VDAgentMessage* _agent_msg;
uint8_t* _agent_msg_data;
uint32_t _agent_msg_pos;
VDAgentMessage* _agent_out_msg;
uint32_t _agent_out_msg_size;
uint32_t _agent_out_msg_pos;
uint32_t _agent_tokens;
AutoRef<AgentTimer> _agent_timer;
uint32_t _agent_caps_size;
uint32_t *_agent_caps;
PeerConnectionOptMap _con_opt_map;
RedPeer::HostAuthOptions _host_auth_opt;
std::string _con_ciphers;
Migrate _migrate;
Mutex _channels_lock;
typedef std::list<ChannelFactory*> Factorys;
Factorys _factorys;
typedef std::list<RedChannel*> Channels;
Channels _channels;
Channels _pending_mig_disconnect_channels;
PixmapCache _pixmap_cache;
uint64_t _pixmap_cache_size;
Mutex _sync_lock;
Condition _sync_condition;
uint64_t _sync_info[SPICE_END_CHANNEL][256];
GlzDecoderWindowDebug _glz_debug;
GlzDecoderWindow _glz_window;
unsigned int _glz_window_size; // in pixels
Mutex _mm_clock_lock;
uint64_t _mm_clock_last_update;
uint32_t _mm_time;
bool _during_migration;
};
#endif

View File

@ -1,122 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RED_DRAWABLE
#define _H_RED_DRAWABLE
#include "common/pixman_utils.h"
#include "pixels_source.h"
#include "utils.h"
typedef uint32_t rgb32_t;
static inline rgb32_t rgb32_make(uint8_t r, uint8_t g, uint8_t b)
{
return (rgb32_t(r) << 16) | (rgb32_t(g) << 8) | b;
}
static inline uint8_t rgb32_get_red(rgb32_t color)
{
return color >> 16;
}
static inline uint8_t rgb32_get_green(rgb32_t color)
{
return color >> 8;
}
static inline uint8_t rgb32_get_blue(rgb32_t color)
{
return color;
}
class RedDrawable: public PixelsSource {
public:
RedDrawable() {}
virtual ~RedDrawable() {}
enum Format {
ARGB32,
RGB32,
RGB16_555,
RGB16_565,
A1,
};
static int format_copy_compatible(Format src, Format dest) {
return src == dest || (src == ARGB32 && dest == RGB32);
}
static int format_to_bpp(Format format) {
if (format == RedDrawable::A1) {
return 1;
} else if (format == RGB16_555 || format == RGB16_565) {
return 16;
} else {
return 32;
}
}
static pixman_format_code_t format_to_pixman(Format format) {
switch (format) {
case RedDrawable::ARGB32:
return PIXMAN_a8r8g8b8;
case RedDrawable::RGB32:
return PIXMAN_x8r8g8b8;
case RedDrawable::RGB16_555:
return PIXMAN_x1r5g5b5;
case RedDrawable::RGB16_565:
return PIXMAN_r5g6b5;
case RedDrawable::A1:
return PIXMAN_a1;
default:
THROW("unsupported format %d", format);
}
}
static Format format_from_surface(uint32_t format) {
switch (format) {
case SPICE_SURFACE_FMT_16_555:
return RedDrawable::RGB16_555;
case SPICE_SURFACE_FMT_16_565:
return RedDrawable::RGB16_565;
case SPICE_SURFACE_FMT_32_xRGB:
return RedDrawable::RGB32;
case SPICE_SURFACE_FMT_32_ARGB:
return RedDrawable::ARGB32;
default:
THROW("Unsupported RedPixman format");
}
}
enum CombineOP {
OP_COPY,
OP_AND,
OP_XOR,
};
virtual RedDrawable::Format get_format() = 0;
void copy_pixels(const PixelsSource& src, int src_x, int src_y, const SpiceRect& dest);
void blend_pixels(const PixelsSource& src, int src_x, int src_y, const SpiceRect& dest);
void combine_pixels(const PixelsSource& src, int src_x, int src_y, const SpiceRect& dest,
CombineOP op);
void fill_rect(const SpiceRect& rect, rgb32_t color);
void frame_rect(const SpiceRect& rect, rgb32_t color);
void erase_rect(const SpiceRect& rect, rgb32_t color);
};
#endif

View File

@ -1,97 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#ifdef __MINGW32__
#undef HAVE_STDLIB_H
#endif
#include <config.h>
#endif
#ifdef WIN32
#include <winsock2.h>
#endif
#include <stdint.h>
#include "common/region.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "common/gdi_canvas.c"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#include "common.h"
#include "red_gdi_canvas.h"
#include "utils.h"
#include "debug.h"
#include "red_pixmap_gdi.h"
GDICanvas::GDICanvas(int width, int height, uint32_t format,
PixmapCache& pixmap_cache, PaletteCache& palette_cache,
GlzDecoderWindow &glz_decoder_window, SurfacesCache &csurfaces)
: Canvas (pixmap_cache, palette_cache, glz_decoder_window, csurfaces)
, _pixmap (0)
{
_pixmap = new RedPixmapGdi(width, height,
RedDrawable::format_from_surface(format),
true);
if (!(_canvas = gdi_canvas_create(width, height, _pixmap->get_dc(),
&_pixmap->get_mutex(),
format, &pixmap_cache.base,
&palette_cache.base,
&csurfaces,
&glz_decoder(),
&jpeg_decoder(),
&zlib_decoder()))) {
THROW("create canvas failed");
}
}
GDICanvas::~GDICanvas()
{
_canvas->ops->destroy(_canvas);
_canvas = NULL;
delete _pixmap;
_pixmap = NULL;
}
void GDICanvas::copy_pixels(const QRegion& region, RedDrawable& dest_dc)
{
pixman_box32_t *rects;
int num_rects;
rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
for (int i = 0; i < num_rects; i++) {
SpiceRect r;
r.left = rects[i].x1;
r.top = rects[i].y1;
r.right = rects[i].x2;
r.bottom = rects[i].y2;
dest_dc.copy_pixels(*_pixmap, r.left, r.top, r);
}
}
void GDICanvas::copy_pixels(const QRegion& region, RedDrawable* dest_dc, const PixmapHeader* pixmap)
{
copy_pixels(region, *dest_dc);
}
CanvasType GDICanvas::get_pixmap_type()
{
return CANVAS_TYPE_GDI;
}

View File

@ -1,53 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_GDICANVAS
#define _H_GDICANVAS
#include "canvas.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "common/gdi_canvas.h"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#include "red_pixmap_gdi.h"
class RedPixmap;
class GDICanvas: public Canvas {
public:
GDICanvas(int width, int height, uint32_t format,
PixmapCache& pixmap_cache, PaletteCache& palette_cache,
GlzDecoderWindow &glz_decoder_window, SurfacesCache &csurfaces);
virtual ~GDICanvas();
virtual void thread_touch() {}
virtual void copy_pixels(const QRegion& region, RedDrawable* dc,
const PixmapHeader* pixmap);
virtual void copy_pixels(const QRegion& region, RedDrawable& dc);
virtual CanvasType get_pixmap_type();
private:
RedPixmapGdi *_pixmap;
RedPixmapGdi *_helper_pixmap;
HDC _dc;
HBITMAP _prev_bitmap;
};
#endif

View File

@ -1,123 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdint.h>
#include <GL/glx.h>
#include "common/region.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "common/gl_canvas.c"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#include "common.h"
#include "red_gl_canvas.h"
#include "utils.h"
#include "debug.h"
#include "red_pixmap_gl.h"
GCanvas::GCanvas(int width, int height, uint32_t format, RedWindow *win,
RenderType rendertype,
PixmapCache& pixmap_cache, PaletteCache& palette_cache,
GlzDecoderWindow &glz_decoder_window, SurfacesCache &csurfaces)
: Canvas(pixmap_cache, palette_cache, glz_decoder_window, csurfaces)
, _pixmap (0)
, _textures_lost (false)
{
_pixmap = new RedPixmapGL(width, height,
RedDrawable::format_from_surface(format),
true, win, rendertype);
if (!(_canvas = gl_canvas_create(width, height,
SPICE_SURFACE_FMT_DEPTH(format),
&pixmap_cache.base,
&palette_cache.base,
&csurfaces,
&glz_decoder(),
&jpeg_decoder(),
&zlib_decoder()))) {
THROW("create canvas failed");
}
}
GCanvas::~GCanvas()
{
gl_canvas_set_textures_lost (_canvas, (int)_textures_lost);
_canvas->ops->destroy(_canvas);
_canvas = NULL;
delete _pixmap;
_pixmap = NULL;
}
void GCanvas::copy_pixels(const QRegion& region, RedDrawable& dest_dc)
{
pixman_box32_t *rects;
int num_rects;
pre_gl_copy();
rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
for (int i = 0; i < num_rects; i++) {
SpiceRect r;
r.left = rects[i].x1;
r.top = rects[i].y1;
r.right = rects[i].x2;
r.bottom = rects[i].y2;
dest_dc.copy_pixels(*_pixmap, r.left, r.top, r);
}
post_gl_copy();
}
void GCanvas::copy_pixels(const QRegion& region, RedDrawable* dest_dc, const PixmapHeader* pixmap)
{
copy_pixels(region, *dest_dc);
}
void GCanvas::touched_bbox(const SpiceRect *bbox)
{
_pixmap->update_texture(bbox);
}
CanvasType GCanvas::get_pixmap_type()
{
return CANVAS_TYPE_GL;
}
void GCanvas::textures_lost()
{
_textures_lost = true;
_pixmap->textures_lost();
}
void GCanvas::touch_context()
{
_pixmap->touch_context();
}
void GCanvas::pre_gl_copy()
{
_pixmap->pre_copy();
}
void GCanvas::post_gl_copy()
{
_pixmap->past_copy();
}

View File

@ -1,66 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_GCANVAS
#define _H_GCANVAS
#include "canvas.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "common/sw_canvas.h"
#include "common/gl_canvas.h"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#include "red_pixmap_gl.h"
#include "red_window.h"
class RedPixmapGL;
class GCanvas: public Canvas {
public:
GCanvas(int width, int height, uint32_t format, RedWindow *win,
RenderType rendertype,
PixmapCache& pixmap_cache, PaletteCache& palette_cache,
GlzDecoderWindow &glz_decoder_window, SurfacesCache &csurfaces);
virtual ~GCanvas();
void set_mode();
void clear();
void thread_touch() {}
void copy_pixels(const QRegion& region, RedDrawable* dc,
const PixmapHeader* pixmap);
void copy_pixels(const QRegion& region, RedDrawable& dc);
virtual void textures_lost();
virtual CanvasType get_pixmap_type();
virtual void touch_context();
virtual void pre_gl_copy();
virtual void post_gl_copy();
void touched_bbox(const SpiceRect *bbox);
private:
void create_pixmap(int width, int height, RedWindow *win,
RenderType rendertype);
void destroy_pixmap();
void destroy();
private:
RedPixmapGL *_pixmap;
bool _textures_lost;
};
#endif

View File

@ -1,152 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RED_KEY
#define _H_RED_KEY
enum RedKey {
REDKEY_INVALID,
REDKEY_ESCAPE,
REDKEY_1,
REDKEY_2,
REDKEY_3,
REDKEY_4,
REDKEY_5,
REDKEY_6,
REDKEY_7,
REDKEY_8,
REDKEY_9,
REDKEY_0,
REDKEY_MINUS,
REDKEY_EQUALS,
REDKEY_BACKSPACE,
REDKEY_TAB,
REDKEY_Q,
REDKEY_W,
REDKEY_E,
REDKEY_R,
REDKEY_T,
REDKEY_Y,
REDKEY_U,
REDKEY_I,
REDKEY_O,
REDKEY_P,
REDKEY_L_BRACKET,
REDKEY_R_BRACKET,
REDKEY_ENTER,
REDKEY_L_CTRL,
REDKEY_A,
REDKEY_S,
REDKEY_D,
REDKEY_F,
REDKEY_G,
REDKEY_H,
REDKEY_J,
REDKEY_K,
REDKEY_L,
REDKEY_SEMICOLON,
REDKEY_QUOTE,
REDKEY_BACK_QUOTE,
REDKEY_L_SHIFT,
REDKEY_BACK_SLASH,
REDKEY_Z,
REDKEY_X,
REDKEY_C,
REDKEY_V,
REDKEY_B,
REDKEY_N,
REDKEY_M,
REDKEY_COMMA,
REDKEY_PERIOD,
REDKEY_SLASH,
REDKEY_R_SHIFT,
REDKEY_PAD_MULTIPLY,
REDKEY_L_ALT,
REDKEY_SPACE,
REDKEY_CAPS_LOCK,
REDKEY_F1,
REDKEY_F2,
REDKEY_F3,
REDKEY_F4,
REDKEY_F5,
REDKEY_F6,
REDKEY_F7,
REDKEY_F8,
REDKEY_F9,
REDKEY_F10,
REDKEY_NUM_LOCK,
REDKEY_SCROLL_LOCK,
REDKEY_PAD_7,
REDKEY_PAD_8,
REDKEY_PAD_9,
REDKEY_PAD_MINUS,
REDKEY_PAD_4,
REDKEY_PAD_5,
REDKEY_PAD_6,
REDKEY_PAD_PLUS,
REDKEY_PAD_1,
REDKEY_PAD_2,
REDKEY_PAD_3,
REDKEY_PAD_0,
REDKEY_PAD_POINT,
REDKEY_EUROPEAN = 0x56,
REDKEY_F11,
REDKEY_F12,
REDKEY_JAPANESE_HIRAGANA_KATAKANA = 0x70,
REDKEY_JAPANESE_BACKSLASH = 0x73,
REDKEY_JAPANESE_HENKAN = 0x79,
REDKEY_JAPANESE_MUHENKAN = 0x7B,
REDKEY_JAPANESE_YEN = 0x7D,
REDKEY_KOREAN_HANGUL_HANJA = 0xf1,
REDKEY_KOREAN_HANGUL = 0xf2,
REDKEY_ESCAPE_BASE = 0x100,
REDKEY_PAD_ENTER = REDKEY_ESCAPE_BASE + 0x1c,
REDKEY_R_CTRL = REDKEY_ESCAPE_BASE + 0x1d,
REDKEY_MUTE = REDKEY_ESCAPE_BASE + 0x20,
REDKEY_FAKE_L_SHIFT = REDKEY_ESCAPE_BASE + 0x2a,
REDKEY_VOLUME_DOWN = REDKEY_ESCAPE_BASE + 0x2e,
REDKEY_VOLUME_UP = REDKEY_ESCAPE_BASE + 0x30,
REDKEY_PAD_DIVIDE = REDKEY_ESCAPE_BASE + 0x35,
REDKEY_FAKE_R_SHIFT = REDKEY_ESCAPE_BASE + 0x36,
REDKEY_CTRL_PRINT_SCREEN = REDKEY_ESCAPE_BASE + 0x37,
REDKEY_R_ALT = REDKEY_ESCAPE_BASE + 0x38,
REDKEY_CTRL_BREAK = REDKEY_ESCAPE_BASE + 0x46,
REDKEY_HOME = REDKEY_ESCAPE_BASE + 0x47,
REDKEY_UP = REDKEY_ESCAPE_BASE + 0x48,
REDKEY_PAGEUP = REDKEY_ESCAPE_BASE + 0x49,
REDKEY_LEFT = REDKEY_ESCAPE_BASE + 0x4b,
REDKEY_RIGHT = REDKEY_ESCAPE_BASE + 0x4d,
REDKEY_END = REDKEY_ESCAPE_BASE + 0x4f,
REDKEY_DOWN = REDKEY_ESCAPE_BASE + 0x50,
REDKEY_PAGEDOWN = REDKEY_ESCAPE_BASE + 0x51,
REDKEY_INSERT = REDKEY_ESCAPE_BASE + 0x52,
REDKEY_DELETE = REDKEY_ESCAPE_BASE + 0x53,
REDKEY_LEFT_CMD = REDKEY_ESCAPE_BASE + 0x5b,
REDKEY_RIGHT_CMD = REDKEY_ESCAPE_BASE + 0x5c,
REDKEY_MENU = REDKEY_ESCAPE_BASE + 0x5d,
REDKEY_PAUSE,
REDKEY_NUM_KEYS
};
#endif

View File

@ -1,463 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef WIN32
#include <winsock2.h>
#endif
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <spice/protocol.h>
#include "common/ssl_verify.h"
#include "common.h"
#include "red_peer.h"
#include "utils.h"
#include "debug.h"
#include "platform_utils.h"
static void SPICE_GNUC_NORETURN ssl_error()
{
unsigned long last_error = ERR_peek_last_error();
ERR_print_errors_fp(stderr);
THROW_ERR(SPICEC_ERROR_CODE_SSL_ERROR, "SSL Error: %s", ERR_error_string(last_error, NULL));
}
RedPeer::RedPeer()
: _peer (INVALID_SOCKET)
, _shut (false)
, _ctx (NULL)
, _ssl (NULL)
{
}
RedPeer::~RedPeer()
{
cleanup();
}
void RedPeer::cleanup()
{
if (_ssl) {
SSL_free(_ssl);
_ssl = NULL;
}
if (_ctx) {
SSL_CTX_free(_ctx);
_ctx = NULL;
}
if (_peer != INVALID_SOCKET) {
closesocket(_peer);
_peer = INVALID_SOCKET;
}
}
void RedPeer::connect_to_peer(const char* host, int portnr)
{
struct addrinfo ai, *result = NULL, *e;
char uaddr[INET6_ADDRSTRLEN+1];
char uport[33], port[33];
int err = 0, rc, no_delay = 1;
ASSERT(_ctx == NULL && _ssl == NULL && _peer == INVALID_SOCKET);
try {
memset(&ai,0, sizeof(ai));
ai.ai_flags = AI_CANONNAME;
#ifdef AI_ADDRCONFIG
ai.ai_flags |= AI_ADDRCONFIG;
#endif
ai.ai_family = PF_UNSPEC;
ai.ai_socktype = SOCK_STREAM;
snprintf(port, sizeof(port), "%d", portnr);
rc = getaddrinfo(host, port, &ai, &result);
if (rc != 0) {
THROW_ERR(SPICEC_ERROR_CODE_GETHOSTBYNAME_FAILED, "cannot resolve host address %s", host);
}
Lock lock(_lock);
_peer = INVALID_SOCKET;
for (e = result; e != NULL; e = e->ai_next) {
if ((_peer = socket(e->ai_family, e->ai_socktype, e->ai_protocol)) == INVALID_SOCKET) {
int err = sock_error();
THROW_ERR(SPICEC_ERROR_CODE_SOCKET_FAILED, "failed to create socket: %s (%d)",
sock_err_message(err), err);
}
if (setsockopt(_peer, IPPROTO_TCP, TCP_NODELAY, (const char*)&no_delay, sizeof(no_delay)) ==
SOCKET_ERROR) {
LOG_WARN("set TCP_NODELAY failed");
}
getnameinfo((struct sockaddr*)e->ai_addr, e->ai_addrlen,
uaddr,INET6_ADDRSTRLEN, uport,32,
NI_NUMERICHOST | NI_NUMERICSERV);
DBG(0, "Trying %s %s", uaddr, uport);
if (::connect(_peer, e->ai_addr, e->ai_addrlen) == SOCKET_ERROR) {
err = sock_error();
LOG_INFO("Connect failed: %s (%d)",
sock_err_message(err), err);
closesocket(_peer);
_peer = INVALID_SOCKET;
continue;
}
DBG(0, "Connected to %s %s", uaddr, uport);
break;
}
lock.unlock();
freeaddrinfo(result);
if (_peer == INVALID_SOCKET) {
THROW_ERR(SPICEC_ERROR_CODE_CONNECT_FAILED, "failed to connect: %s (%d)",
sock_err_message(err), err);
}
_serial = 0;
} catch (...) {
Lock lock(_lock);
cleanup();
throw;
}
}
void RedPeer::connect_unsecure(const char* host, int portnr)
{
connect_to_peer(host, portnr);
ASSERT(_ctx == NULL && _ssl == NULL && _peer != INVALID_SOCKET);
LOG_INFO("Connected to %s %d", host, portnr);
}
void RedPeer::connect_secure(const ConnectionOptions& options, const char* host)
{
int return_code;
SPICE_SSL_VERIFY_OP auth_flags;
SpiceOpenSSLVerify* verify = NULL;
int portnr = options.secure_port;
connect_to_peer(host, portnr);
ASSERT(_ctx == NULL && _ssl == NULL && _peer != INVALID_SOCKET);
LOG_INFO("Connected to %s %d", host, portnr);
try {
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
const SSL_METHOD *ssl_method = TLSv1_method();
#else
SSL_METHOD *ssl_method = TLSv1_method();
#endif
_ctx = SSL_CTX_new(ssl_method);
if (_ctx == NULL) {
ssl_error();
}
auth_flags = options.host_auth.type_flags;
if ((auth_flags & SPICE_SSL_VERIFY_OP_HOSTNAME) ||
(auth_flags & SPICE_SSL_VERIFY_OP_SUBJECT)) {
std::string CA_file = options.host_auth.CA_file;
ASSERT(!CA_file.empty());
return_code = SSL_CTX_load_verify_locations(_ctx, CA_file.c_str(), NULL);
if (return_code != 1) {
if (auth_flags & SPICE_SSL_VERIFY_OP_PUBKEY) {
LOG_WARN("SSL_CTX_load_verify_locations failed, CA_file=%s. "
"only pubkey authentication is active", CA_file.c_str());
auth_flags = SPICE_SSL_VERIFY_OP_PUBKEY;
}
else {
LOG_ERROR("SSL_CTX_load_verify_locations failed CA_file=%s", CA_file.c_str());
ssl_error();
}
}
}
return_code = SSL_CTX_set_cipher_list(_ctx, options.ciphers.c_str());
if (return_code != 1) {
LOG_ERROR("SSL_CTX_set_cipher_list failed, ciphers=%s", options.ciphers.c_str());
ssl_error();
}
_ssl = SSL_new(_ctx);
if (!_ssl) {
THROW("create ssl failed");
}
verify = spice_openssl_verify_new(
_ssl, auth_flags,
host,
(char*)&options.host_auth.host_pubkey[0],
options.host_auth.host_pubkey.size(),
options.host_auth.host_subject.c_str());
BIO* sbio = BIO_new_socket(_peer, BIO_NOCLOSE);
if (!sbio) {
THROW("alloc new socket bio failed");
}
SSL_set_bio(_ssl, sbio, sbio);
return_code = SSL_connect(_ssl);
if (return_code <= 0) {
int ssl_error_code = SSL_get_error(_ssl, return_code);
LOG_ERROR("failed to connect w/SSL, ssl_error %s",
ERR_error_string(ssl_error_code, NULL));
ssl_error();
}
} catch (...) {
Lock lock(_lock);
spice_openssl_verify_free(verify);
cleanup();
throw;
}
spice_openssl_verify_free(verify);
}
void RedPeer::shutdown()
{
if (_peer != INVALID_SOCKET) {
if (_ssl) {
SSL_shutdown(_ssl);
}
::shutdown(_peer, SHUT_RDWR);
}
_shut = true;
}
void RedPeer::disconnect()
{
Lock lock(_lock);
shutdown();
}
void RedPeer::close()
{
Lock lock(_lock);
if (_peer != INVALID_SOCKET) {
if (_ctx) {
SSL_free(_ssl);
_ssl = NULL;
SSL_CTX_free(_ctx);
_ctx = NULL;
}
closesocket(_peer);
_peer = INVALID_SOCKET;
}
}
void RedPeer::swap(RedPeer* other)
{
Lock lock(_lock);
SOCKET temp_peer = _peer;
SSL_CTX *temp_ctx = _ctx;
SSL *temp_ssl = _ssl;
_peer = other->_peer;
other->_peer = temp_peer;
if (_ctx) {
_ctx = other->_ctx;
_ssl = other->_ssl;
other->_ctx = temp_ctx;
other->_ssl = temp_ssl;
}
if (_shut) {
shutdown();
}
}
uint32_t RedPeer::receive(uint8_t *buf, uint32_t size)
{
uint8_t *pos = buf;
while (size) {
int now;
if (_ctx == NULL) {
if ((now = recv(_peer, (char *)pos, size, 0)) <= 0) {
int err = sock_error();
if (now == SOCKET_ERROR && err == WOULDBLOCK_ERR) {
break;
}
if (now == 0 || err == SHUTDOWN_ERR) {
throw RedPeer::DisconnectedException();
}
if (err == INTERRUPTED_ERR) {
continue;
}
THROW_ERR(SPICEC_ERROR_CODE_RECV_FAILED, "%s (%d)", sock_err_message(err), err);
}
size -= now;
pos += now;
} else {
if ((now = SSL_read(_ssl, pos, size)) <= 0) {
int ssl_error = SSL_get_error(_ssl, now);
if (ssl_error == SSL_ERROR_WANT_READ) {
break;
}
if (ssl_error == SSL_ERROR_SYSCALL) {
int err = sock_error();
if (now == -1) {
if (err == WOULDBLOCK_ERR) {
break;
}
if (err == INTERRUPTED_ERR) {
continue;
}
}
if (now == 0 || (now == -1 && err == SHUTDOWN_ERR)) {
throw RedPeer::DisconnectedException();
}
THROW_ERR(SPICEC_ERROR_CODE_SEND_FAILED, "%s (%d)", sock_err_message(err), err);
} else if (ssl_error == SSL_ERROR_ZERO_RETURN) {
throw RedPeer::DisconnectedException();
}
THROW_ERR(SPICEC_ERROR_CODE_RECV_FAILED, "ssl error %d", ssl_error);
}
size -= now;
pos += now;
}
}
return pos - buf;
}
RedPeer::CompoundInMessage* RedPeer::receive()
{
SpiceDataHeader header;
AutoRef<CompoundInMessage> message;
receive((uint8_t*)&header, sizeof(SpiceDataHeader));
message.reset(new CompoundInMessage(header.serial, header.type, header.size, header.sub_list));
receive((*message)->data(), (*message)->compound_size());
return message.release();
}
uint32_t RedPeer::send(uint8_t *buf, uint32_t size)
{
uint8_t *pos = buf;
while (size) {
int now;
if (_ctx == NULL) {
if ((now = ::send(_peer, (char *)pos, size, 0)) == SOCKET_ERROR) {
int err = sock_error();
if (err == WOULDBLOCK_ERR) {
break;
}
if (err == SHUTDOWN_ERR) {
throw RedPeer::DisconnectedException();
}
if (err == INTERRUPTED_ERR) {
continue;
}
THROW_ERR(SPICEC_ERROR_CODE_SEND_FAILED, "%s (%d)", sock_err_message(err), err);
}
size -= now;
pos += now;
} else {
if ((now = SSL_write(_ssl, pos, size)) <= 0) {
int ssl_error = SSL_get_error(_ssl, now);
if (ssl_error == SSL_ERROR_WANT_WRITE) {
break;
}
if (ssl_error == SSL_ERROR_SYSCALL) {
int err = sock_error();
if (now == -1) {
if (err == WOULDBLOCK_ERR) {
break;
}
if (err == INTERRUPTED_ERR) {
continue;
}
}
if (now == 0 || (now == -1 && err == SHUTDOWN_ERR)) {
throw RedPeer::DisconnectedException();
}
THROW_ERR(SPICEC_ERROR_CODE_SEND_FAILED, "%s (%d)", sock_err_message(err), err);
} else if (ssl_error == SSL_ERROR_ZERO_RETURN) {
throw RedPeer::DisconnectedException();
}
THROW_ERR(SPICEC_ERROR_CODE_SEND_FAILED, "ssl error %d", ssl_error);
}
size -= now;
pos += now;
}
}
return pos - buf;
}
uint32_t RedPeer::do_send(RedPeer::OutMessage& message, uint32_t skip_bytes)
{
uint8_t *data;
int free_data;
size_t len;
uint32_t res;
data = spice_marshaller_linearize(message.marshaller(), skip_bytes,
&len, &free_data);
res = send(data, len);
if (free_data) {
free(data);
}
return res;
}
uint32_t RedPeer::send(RedPeer::OutMessage& message)
{
message.header().serial = ++_serial;
message.header().size = message.message_size() - sizeof(SpiceDataHeader);
return do_send(message, 0);
}
RedPeer::OutMessage::OutMessage(uint32_t type)
: _marshaller (spice_marshaller_new())
{
SpiceDataHeader *header;
header = (SpiceDataHeader *)
spice_marshaller_reserve_space(_marshaller, sizeof(SpiceDataHeader));
spice_marshaller_set_base(_marshaller, sizeof(SpiceDataHeader));
header->type = type;
header->sub_list = 0;
}
void RedPeer::OutMessage::reset(uint32_t type)
{
spice_marshaller_reset(_marshaller);
SpiceDataHeader *header;
header = (SpiceDataHeader *)
spice_marshaller_reserve_space(_marshaller, sizeof(SpiceDataHeader));
spice_marshaller_set_base(_marshaller, sizeof(SpiceDataHeader));
header->type = type;
header->sub_list = 0;
}
RedPeer::OutMessage::~OutMessage()
{
spice_marshaller_destroy(_marshaller);
}

View File

@ -1,209 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_REDPEER
#define _H_REDPEER
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <spice/protocol.h>
#include "common/marshaller.h"
#include "common/ssl_verify.h"
#include "common.h"
#include "process_loop.h"
#include "threads.h"
#include "platform_utils.h"
#include "debug.h"
class RedPeer: protected EventSources::Socket {
public:
RedPeer();
virtual ~RedPeer();
class InMessage;
class CompoundInMessage;
class OutMessage;
class DisconnectedException {};
class HostAuthOptions {
public:
typedef std::vector<uint8_t> PublicKey;
typedef std::pair<std::string, std::string> CertFieldValuePair;
typedef std::list<CertFieldValuePair> CertFieldValueList;
HostAuthOptions() : type_flags(SPICE_SSL_VERIFY_OP_NONE) {}
public:
SPICE_SSL_VERIFY_OP type_flags;
PublicKey host_pubkey;
std::string host_subject;
std::string CA_file;
};
class ConnectionOptions {
public:
enum Type {
CON_OP_INVALID,
CON_OP_SECURE,
CON_OP_UNSECURE,
CON_OP_BOTH,
};
ConnectionOptions(Type in_type, int in_port, int in_sport,
int in_protocol,
const HostAuthOptions& in_host_auth,
const std::string& in_ciphers)
: type (in_type)
, unsecure_port (in_port)
, secure_port (in_sport)
, protocol (in_protocol)
, host_auth (in_host_auth)
, ciphers (in_ciphers)
{
}
virtual ~ConnectionOptions() {}
bool allow_secure() const
{
return (type == CON_OP_BOTH || type == CON_OP_SECURE) && secure_port != -1;
}
bool allow_unsecure() const
{
return (type == CON_OP_BOTH || type == CON_OP_UNSECURE) && unsecure_port != -1;
}
public:
Type type;
int unsecure_port;
int secure_port;
int protocol; // 0 == auto
HostAuthOptions host_auth; // for secure connection
std::string ciphers;
};
void connect_unsecure(const char* host, int port);
void connect_secure(const ConnectionOptions& options, const char* host);
void disconnect();
void swap(RedPeer* other);
void close();
void enable() { _shut = false;}
virtual CompoundInMessage* receive();
uint32_t do_send(OutMessage& message, uint32_t skip_bytes);
uint32_t send(OutMessage& message);
uint32_t receive(uint8_t* buf, uint32_t size);
uint32_t send(uint8_t* buf, uint32_t size);
protected:
virtual void on_event() {}
virtual int get_socket() { return _peer;}
void cleanup();
private:
void connect_to_peer(const char* host, int port);
void shutdown();
private:
SOCKET _peer;
Mutex _lock;
bool _shut;
uint64_t _serial;
SSL_CTX *_ctx;
SSL *_ssl;
};
class RedPeer::InMessage {
public:
InMessage(uint16_t type, uint32_t size, uint8_t * data)
: _type (type)
, _size (size)
, _data (data)
{
}
virtual ~InMessage() {}
uint16_t type() { return _type;}
uint8_t* data() { return _data;}
virtual uint32_t size() { return _size;}
protected:
uint16_t _type;
uint32_t _size;
uint8_t* _data;
};
class RedPeer::CompoundInMessage: public RedPeer::InMessage {
public:
CompoundInMessage(uint64_t _serial, uint16_t type, uint32_t size, uint32_t sub_list)
: InMessage(type, size, new uint8_t[size])
, _refs (1)
, _serial (_serial)
, _sub_list (sub_list)
{
}
RedPeer::InMessage* ref() { _refs++; return this;}
void unref() {if (!--_refs) delete this;}
uint64_t serial() { return _serial;}
uint32_t sub_list() { return _sub_list;}
virtual uint32_t size() { return _sub_list ? _sub_list : _size;}
uint32_t compound_size() {return _size;}
protected:
virtual ~CompoundInMessage() { delete[] _data;}
private:
int _refs;
uint64_t _serial;
uint32_t _sub_list;
};
class RedPeer::OutMessage {
public:
OutMessage(uint32_t type);
virtual ~OutMessage();
SpiceMarshaller *marshaller() { return _marshaller;}
void reset(uint32_t type);
private:
uint32_t message_size() { return spice_marshaller_get_total_size(_marshaller);}
uint8_t* base() { return spice_marshaller_get_ptr(_marshaller);}
SpiceDataHeader& header() { return *(SpiceDataHeader *)base();}
protected:
SpiceMarshaller *_marshaller;
friend class RedPeer;
friend class RedChannel;
};
#endif

View File

@ -1,67 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RED_PIXMAP
#define _H_RED_PIXMAP
#include "red_drawable.h"
#include "utils.h"
class RedPixmap: public RedDrawable {
public:
RedPixmap(int width, int height, Format format, bool top_bottom);
virtual ~RedPixmap();
virtual SpicePoint get_size() { SpicePoint pt = {_width, _height}; return pt;}
int get_width() { return _width;}
int get_height() { return _height;}
int get_stride() { return _stride;}
uint8_t* get_data() { return _data;}
bool is_big_endian_bits();
virtual RedDrawable::Format get_format() { return _format; }
bool equal(const RedPixmap &other, const SpiceRect &rect) const {
spice_debug("l:%d r:%d t:%d b:%d", rect.left, rect.right, rect.top, rect.bottom);
for (int x = rect.left; x < rect.right; ++x)
for (int y = rect.top; y < rect.bottom; ++y) {
for (int i = 0; i < 3; i++) { // ignore alpha
int p = x * 4 + y * _stride + i;
if (other._data[p] != _data[p]) {
spice_printerr("equal fails at (+%d+%d) +%d+%d:%d in %dx%d",
rect.left, rect.top, x-rect.left, y-rect.top, i,
_width-rect.left, _height-rect.top);
if (getenv("DIFFBP"))
SPICE_BREAKPOINT();
return false;
}
}
}
return true;
}
protected:
Format _format;
int _width;
int _height;
int _stride;
bool _top_bottom;
uint8_t* _data;
};
#endif

View File

@ -1,35 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RED_PIXMAP_GDI
#define _H_RED_PIXMAP_GDI
#include "red_pixmap.h"
class RecurciveMutex;
class RedPixmapGdi: public RedPixmap {
public:
RedPixmapGdi(int width, int height, Format format, bool top_bottom);
HDC get_dc();
void *get_memptr();
~RedPixmapGdi();
RecurciveMutex& get_mutex();
};
#endif

View File

@ -1,49 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RED_PIXMAP_GL
#define _H_RED_PIXMAP_GL
#include "red_pixmap.h"
#include "red_window.h"
enum RenderType {
RENDER_TYPE_PBUFF,
RENDER_TYPE_FBO,
};
class RedPixmapGL: public RedPixmap {
public:
RedPixmapGL(int width, int height, Format format, bool top_bottom,
RedWindow *win, RenderType rendertype);
void textures_lost();
void touch_context();
void update_texture(const SpiceRect *bbox);
void pre_copy();
void past_copy();
~RedPixmapGL();
private:
RedGlContext _glcont;
GLint _prev_tex;
GLint _prev_matrix_mode;
bool _tex_enabled;
bool _textures_lost;
};
#endif

View File

@ -1,30 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RED_PIXMAP_SW
#define _H_RED_PIXMAP_SW
#include "red_pixmap.h"
#include "red_window.h"
class RedPixmapSw: public RedPixmap {
public:
RedPixmapSw(int width, int height, Format format, bool top_bottom, RedWindow *window);
~RedPixmapSw();
};
#endif

View File

@ -1,112 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdint.h>
#ifdef WIN32
#include <winsock2.h>
#endif
#include "common/region.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "common/sw_canvas.c"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
#include "common.h"
#include "red_window.h"
#include "red_sw_canvas.h"
#include "utils.h"
#include "debug.h"
#include "red_pixmap_sw.h"
SCanvas::SCanvas(bool onscreen,
int width, int height, uint32_t format, RedWindow *win,
PixmapCache& pixmap_cache, PaletteCache& palette_cache,
GlzDecoderWindow &glz_decoder_window, SurfacesCache& csurfaces)
: Canvas (pixmap_cache, palette_cache, glz_decoder_window, csurfaces)
, _pixmap (0)
{
if (onscreen) {
_pixmap = new RedPixmapSw(width, height,
RedDrawable::format_from_surface(format),
true, win);
_canvas = canvas_create_for_data(width, height, format,
_pixmap->get_data(),
_pixmap->get_stride(),
&pixmap_cache.base,
&palette_cache.base,
&csurfaces,
&glz_decoder(),
&jpeg_decoder(),
&zlib_decoder());
} else {
_canvas = canvas_create(width, height, format,
&pixmap_cache.base,
&palette_cache.base,
&csurfaces,
&glz_decoder(),
&jpeg_decoder(),
&zlib_decoder());
}
if (_canvas == NULL) {
THROW("create canvas failed");
}
}
SCanvas::~SCanvas()
{
_canvas->ops->destroy(_canvas);
_canvas = NULL;
if (_pixmap) {
delete _pixmap;
_pixmap = NULL;
}
}
void SCanvas::copy_pixels(const QRegion& region, RedDrawable& dest_dc)
{
pixman_box32_t *rects;
int num_rects;
ASSERT(_pixmap != NULL);
rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
for (int i = 0; i < num_rects; i++) {
SpiceRect r;
r.left = rects[i].x1;
r.top = rects[i].y1;
r.right = rects[i].x2;
r.bottom = rects[i].y2;
dest_dc.copy_pixels(*_pixmap, r.left, r.top, r);
}
}
void SCanvas::copy_pixels(const QRegion& region, RedDrawable* dest_dc, const PixmapHeader* pixmap)
{
copy_pixels(region, *dest_dc);
}
CanvasType SCanvas::get_pixmap_type()
{
return CANVAS_TYPE_SW;
}

View File

@ -1,50 +0,0 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_CCANVAS
#define _H_CCANVAS
#include "canvas.h"
#define SPICE_CANVAS_INTERNAL
#define SW_CANVAS_CACHE
#include "common/sw_canvas.h"
#undef SW_CANVAS_CACHE
#undef SPICE_CANVAS_INTERNAL
class RedPixmap;
class SCanvas: public Canvas {
public:
SCanvas(bool onscreen,
int width, int height, uint32_t format, RedWindow *win,
PixmapCache& pixmap_cache, PaletteCache& palette_cache,
GlzDecoderWindow &glz_decoder_window, SurfacesCache &csurfaces);
virtual ~SCanvas();
virtual void thread_touch() {}
virtual void copy_pixels(const QRegion& region, RedDrawable* dc,
const PixmapHeader* pixmap);
virtual void copy_pixels(const QRegion& region, RedDrawable& dc);
virtual CanvasType get_pixmap_type();
private:
RedPixmap *_pixmap;
};
#endif

View File

@ -1,37 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RED_TYPES
#define _H_RED_TYPES
struct PixmapHeader {
uint8_t* data;
int width;
int height;
int stride;
};
struct IconHeader {
int width;
int height;
uint8_t* pixmap;
uint8_t* mask;
};
class RedDrawable;
#endif

View File

@ -1,200 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_RED_WINDOW
#define _H_RED_WINDOW
#include "red_drawable.h"
#include <spice/protocol.h>
#include "red_key.h"
#include "red_window_p.h"
#include "cursor.h"
class Menu;
class Icon;
class RedWindow: public RedDrawable, private RedWindow_p {
public:
class Listener;
enum {
DEFAULT_SCREEN = -1,
};
RedWindow(RedWindow::Listener& listener, int screen_id = DEFAULT_SCREEN);
virtual ~RedWindow();
void move_and_resize(int x, int y, int width, int height);
void resize(int width, int height);
void move(int x, int y);
void position_after(RedWindow *after);
void raise();
void show(int screen_id);
void external_show();
void hide();
void minimize();
void activate();
void set_title(std::string& title);
void set_icon(Icon *icon);
virtual RedDrawable::Format get_format();
enum Type {
TYPE_INVALID,
TYPE_NORMAL,
TYPE_FULLSCREEN,
};
void set_type(Type type) { _type = type;}
SpicePoint get_position();
virtual SpicePoint get_size();
bool get_mouse_anchor_point(SpicePoint& pt);
void set_mouse_position(int x, int y);
void set_cursor(LocalCursor* local_cursor);
void hide_cursor();
void show_cursor();
void capture_mouse();
void release_mouse();
void start_key_interception();
void stop_key_interception();
int set_menu(Menu* menu);
#ifdef USE_OPENGL
void untouch_context();
RedGlContext create_context_gl();
RedPbuffer create_pbuff(int width, int height);
void set_render_pbuff(RedPbuffer pbuff);
void set_render_fbo(GLuint fbo);
void set_gl_context(RedGlContext context);
void set_type_gl();
void unset_type_gl();
void swap_gl();
#endif
int get_screen_num();
static void init();
static void cleanup();
Listener& get_listener() { return _listener;}
private:
void on_focus_in();
void on_focus_out();
void on_pointer_enter(int x, int y, unsigned int buttons_state);
void on_pointer_leave();
void do_start_key_interception();
void do_stop_key_interception();
private:
Listener& _listener;
SpicePoint _window_size;
Type _type;
LocalCursor* _local_cursor;
bool _cursor_visible;
bool _trace_key_interception;
bool _key_interception_on;
Menu* _menu;
friend class RedWindow_p;
};
class RedWindow::Listener {
public:
virtual ~Listener() {}
virtual void on_exposed_rect(const SpiceRect& area) = 0;
virtual void on_pointer_enter(int x, int y, unsigned int buttons_state) = 0;
virtual void on_pointer_motion(int x, int y, unsigned int buttons_state) = 0;
virtual void on_pointer_leave() = 0;
virtual void on_mouse_button_press(SpiceMouseButton button, unsigned int buttons_state) = 0;
virtual void on_mouse_button_release(SpiceMouseButton button, unsigned int buttons_state) = 0;
virtual void on_key_press(RedKey key) = 0;
virtual void on_key_release(RedKey key) = 0;
virtual void on_char(uint32_t ch) = 0;
virtual void on_deactivate() = 0;
virtual void on_activate() = 0;
virtual void on_start_key_interception() = 0;
virtual void on_stop_key_interception() = 0;
virtual void enter_modal_loop() = 0;
virtual void exit_modal_loop() = 0;
virtual void pre_migrate() { }
virtual void post_migrate() { }
};
/*class REGION {
void get_bbox(SpiceRect& bbox) const;
bool contains_point(int x, int y) const;
};*/
template <class REGION>
static bool find_anchor_point(const REGION& region, SpicePoint& pt)
{
static const unsigned int lookup_size = 20;
unsigned int width;
unsigned int height;
SpiceRect bbox;
region.get_bbox(bbox);
width = bbox.right - bbox.left;
height = bbox.bottom - bbox.top;
int div = 2;
for (;;) {
unsigned int h_unit;
unsigned int v_unit;
if ((v_unit = height / div) * 2 < lookup_size || (h_unit = width / div) * 2 < lookup_size) {
return false;
}
for (unsigned int y = v_unit; y < v_unit * div; y += v_unit * 2) {
for (unsigned int x = h_unit; x < h_unit * div; x += h_unit * 2) {
if (!region.contains_point(bbox.left + x, bbox.top + y)) {
continue;
}
SpiceRect r;
r.left = bbox.left + x - lookup_size / 2;
r.right = r.left + lookup_size;
r.top = bbox.top + y - lookup_size / 2;
r.bottom = r.top + lookup_size;
if (!region.contains_point(r.left, r.top) ||
!region.contains_point(r.right, r.top) ||
!region.contains_point(r.left, r.bottom) ||
!region.contains_point(r.right, r.bottom)) {
continue;
}
pt.x = bbox.left + x;
pt.y = bbox.top + y;
return true;
}
}
div *= 2;
}
}
#endif

View File

@ -1,944 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "screen.h"
#include "application.h"
#include "screen_layer.h"
#include "utils.h"
#include "debug.h"
#include "monitor.h"
#include "red_pixmap_sw.h"
#include "resource.h"
#include "icon.h"
class UpdateEvent: public Event {
public:
UpdateEvent(int screen) : _screen (screen) {}
virtual void response(AbstractProcessLoop& events_loop)
{
Application* app = static_cast<Application*>(events_loop.get_owner());
RedScreen* screen = app->find_screen(_screen);
if (screen) {
screen->update();
}
}
private:
int _screen;
};
class LayerChangedEvent: public Event {
public:
LayerChangedEvent (int screen) : _screen (screen) {}
virtual void response(AbstractProcessLoop& events_loop)
{
Application* app = static_cast<Application*>(events_loop.get_owner());
RedScreen* screen = app->find_screen(_screen);
if (screen) {
Lock lock(screen->_layer_changed_lock);
screen->_active_layer_change_event = false;
lock.unlock();
if (screen->_pointer_on_screen) {
screen->update_pointer_layer();
}
}
}
private:
int _screen;
};
void UpdateTimer::response(AbstractProcessLoop& events_loop)
{
_screen->periodic_update();
}
RedScreen::RedScreen(Application& owner, int id, const std::string& name, int width, int height)
: _owner (owner)
, _id (id)
, _refs (1)
, _window (*this)
, _active (false)
, _full_screen (false)
, _out_of_sync (false)
, _frame_area (false)
, _periodic_update (false)
, _key_interception (false)
, _update_by_timer (true)
, _size_locked (false)
, _menu_needs_update (false)
, _force_update_timer (0)
, _update_timer (new UpdateTimer(this))
, _composit_area (NULL)
, _update_mark (1)
, _monitor (NULL)
, _default_cursor (NULL)
, _inactive_cursor (NULL)
, _pixel_format_index (0)
, _update_interrupt_trigger (NULL)
, _pointer_layer (NULL)
, _mouse_captured (false)
, _active_layer_change_event (false)
, _pointer_on_screen (false)
{
region_init(&_dirty_region);
set_name(name);
_size.x = width;
_size.y = height;
_origin.x = _origin.y = 0;
create_composit_area();
_window.resize(_size.x, _size.y);
save_position();
if ((_default_cursor = Platform::create_default_cursor()) == NULL) {
THROW("create default cursor failed");
}
if ((_inactive_cursor = Platform::create_inactive_cursor()) == NULL) {
THROW("create inactive cursor failed");
}
_window.set_cursor(_default_cursor);
update_menu();
AutoRef<Icon> icon(Platform::load_icon(RED_ICON_RES_ID));
_window.set_icon(*icon);
_window.start_key_interception();
}
RedScreen::~RedScreen()
{
bool captured = is_mouse_captured();
_window.stop_key_interception();
relase_mouse();
destroy_composit_area();
_owner.deactivate_interval_timer(*_update_timer);
_owner.on_screen_destroyed(_id, captured);
region_destroy(&_dirty_region);
if (_default_cursor) {
_default_cursor->unref();
}
if (_inactive_cursor) {
_inactive_cursor->unref();
}
}
void RedScreen::show(bool activate, RedScreen* pos)
{
_window.position_after((pos) ? &pos->_window : NULL);
show();
if (activate) {
_window.activate();
}
}
RedScreen* RedScreen::ref()
{
++_refs;
return this;
}
void RedScreen::unref()
{
if (!--_refs) {
delete this;
}
}
void RedScreen::destroy_composit_area()
{
if (_composit_area) {
delete _composit_area;
_composit_area = NULL;
}
}
void RedScreen::create_composit_area()
{
destroy_composit_area();
_composit_area = new RedPixmapSw(_size.x, _size.y, _window.get_format(),
false, &_window);
}
void RedScreen::adjust_window_rect(int x, int y)
{
_window.move_and_resize(x, y, _size.x, _size.y);
}
void RedScreen::resize(int width, int height)
{
RecurciveLock lock(_update_lock);
_size.x = width;
_size.y = height;
create_composit_area();
if (_full_screen) {
__show_full_screen();
} else {
bool cuptur = is_mouse_captured();
if (cuptur) {
relase_mouse();
}
_window.resize(_size.x, _size.y);
if (_active && cuptur) {
capture_mouse();
}
}
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::string& name)
{
if (!name.empty()) {
string_printf(_name, name.c_str(), _id);
}
_window.set_title(_name);
}
void RedScreen::on_layer_changed(ScreenLayer& layer)
{
Lock lock(_layer_changed_lock);
if (_active_layer_change_event) {
return;
}
_active_layer_change_event = true;
AutoRef<LayerChangedEvent> change_event(new LayerChangedEvent(_id));
_owner.push_event(*change_event);
}
void RedScreen::attach_layer(ScreenLayer& layer)
{
RecurciveLock lock(_update_lock);
int order = layer.z_order();
if ((int)_layers.size() < order + 1) {
_layers.resize(order + 1);
}
if (_layers[order]) {
THROW("layer in use");
}
layer.set_screen(this);
_layers[order] = &layer;
ref();
lock.unlock();
layer.invalidate();
if (_pointer_on_screen) {
update_pointer_layer();
}
}
void RedScreen::detach_layer(ScreenLayer& layer)
{
bool need_pointer_layer_update = false;
if (_pointer_layer == &layer) {
_pointer_layer->on_pointer_leave();
_pointer_layer = NULL;
need_pointer_layer_update = true;
}
RecurciveLock lock(_update_lock);
int order = layer.z_order();
if ((int)_layers.size() < order + 1 || _layers[order] != &layer) {
THROW("not found");
}
QRegion layer_area;
region_clone(&layer_area, &layer.area());
_layers[order]->set_screen(NULL);
_layers[order] = NULL;
lock.unlock();
invalidate(layer_area);
region_destroy(&layer_area);
unref();
if (need_pointer_layer_update && !update_pointer_layer()) {
_window.set_cursor(_inactive_cursor);
}
}
void RedScreen::composit_to_screen(RedDrawable& win_dc, const QRegion& region)
{
pixman_box32_t *rects;
int num_rects;
rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
for (int i = 0; i < num_rects; i++) {
SpiceRect r;
r.left = rects[i].x1;
r.top = rects[i].y1;
r.right = rects[i].x2;
r.bottom = rects[i].y2;
win_dc.copy_pixels(*_composit_area, r.left, r.top, r);
}
}
void RedScreen::notify_new_size()
{
for (int i = 0; i < (int)_layers.size(); i++) {
if (!_layers[i]) {
continue;
}
_layers[i]->on_size_changed();
}
}
inline void RedScreen::begin_update(QRegion& direct_rgn, QRegion& composit_rgn,
QRegion& frame_rgn)
{
region_init(&composit_rgn);
RecurciveLock lock(_update_lock);
region_clone(&direct_rgn, &_dirty_region);
region_clear(&_dirty_region);
_update_mark++;
lock.unlock();
QRegion rect_rgn;
SpiceRect r;
r.top = r.left = 0;
r.right = _size.x;
r.bottom = _size.y;
region_init(&rect_rgn);
region_add(&rect_rgn, &r);
if (_frame_area) {
region_clone(&frame_rgn, &direct_rgn);
region_exclude(&frame_rgn, &rect_rgn);
}
region_and(&direct_rgn, &rect_rgn);
region_destroy(&rect_rgn);
for (int i = _layers.size() - 1; i >= 0; i--) {
ScreenLayer* layer;
if (!(layer = _layers[i])) {
continue;
}
layer->begin_update(direct_rgn, composit_rgn);
}
}
inline void RedScreen::update_done()
{
for (unsigned int i = 0; i < _layers.size(); i++) {
ScreenLayer* layer;
if (!(layer = _layers[i])) {
continue;
}
layer->on_update_completion(_update_mark - 1);
}
#ifdef USE_OPENGL
_window.swap_gl();
#endif
}
inline void RedScreen::update_composit(QRegion& composit_rgn)
{
erase_background(*_composit_area, composit_rgn);
for (int i = 0; i < (int)_layers.size(); i++) {
ScreenLayer* layer;
if (!(layer = _layers[i])) {
continue;
}
QRegion& dest_region = layer->composit_area();
region_or(&composit_rgn, &dest_region);
layer->copy_pixels(dest_region, *_composit_area);
}
}
inline void RedScreen::draw_direct(RedDrawable& win_dc, QRegion& direct_rgn, QRegion& composit_rgn,
QRegion& frame_rgn)
{
erase_background(win_dc, direct_rgn);
if (_frame_area) {
erase_background(win_dc, frame_rgn);
region_destroy(&frame_rgn);
}
for (int i = 0; i < (int)_layers.size(); i++) {
ScreenLayer* layer;
if (!(layer = _layers[i])) {
continue;
}
QRegion& dest_region = layer->direct_area();
layer->copy_pixels(dest_region, win_dc);
}
}
void RedScreen::periodic_update()
{
bool need_update;
RecurciveLock lock(_update_lock);
if (is_dirty()) {
need_update = true;
} else {
if (!_force_update_timer) {
_owner.deactivate_interval_timer(*_update_timer);
_periodic_update = false;
}
need_update = false;
}
lock.unlock();
if (need_update) {
if (update_by_interrupt()) {
interrupt_update();
} else {
update();
}
}
}
void RedScreen::activate_timer()
{
RecurciveLock lock(_update_lock);
if (_periodic_update) {
return;
}
_periodic_update = true;
lock.unlock();
_owner.activate_interval_timer(*_update_timer, 1000 / 30);
}
void RedScreen::update()
{
if (is_out_of_sync()) {
return;
}
QRegion direct_rgn;
QRegion composit_rgn;
QRegion frame_rgn;
begin_update(direct_rgn, composit_rgn, frame_rgn);
update_composit(composit_rgn);
draw_direct(_window, direct_rgn, composit_rgn, frame_rgn);
composit_to_screen(_window, composit_rgn);
update_done();
region_destroy(&direct_rgn);
region_destroy(&composit_rgn);
if (_update_by_timer) {
activate_timer();
}
}
bool RedScreen::_invalidate(const SpiceRect& rect, bool urgent, uint64_t& update_mark)
{
RecurciveLock lock(_update_lock);
bool update_triger = !is_dirty() && (urgent || !_periodic_update);
region_add(&_dirty_region, &rect);
update_mark = _update_mark;
return update_triger;
}
uint64_t RedScreen::invalidate(const SpiceRect& rect, bool urgent)
{
uint64_t update_mark;
if (_invalidate(rect, urgent, update_mark)) {
if (!urgent && _update_by_timer) {
activate_timer();
} else {
if (update_by_interrupt()) {
interrupt_update();
} else {
AutoRef<UpdateEvent> update_event(new UpdateEvent(_id));
_owner.push_event(*update_event);
}
}
}
return update_mark;
}
void RedScreen::invalidate(const QRegion &region)
{
pixman_box32_t *rects, *end;
int num_rects;
rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
end = rects + num_rects;
while (rects != end) {
SpiceRect r;
r.left = rects->x1;
r.top = rects->y1;
r.right = rects->x2;
r.bottom = rects->y2;
rects++;
invalidate(r, false);
}
}
inline void RedScreen::erase_background(RedDrawable& dc, const QRegion& composit_rgn)
{
pixman_box32_t *rects;
int num_rects;
rects = pixman_region32_rectangles((pixman_region32_t *)&composit_rgn, &num_rects);
for (int i = 0; i < num_rects; i++) {
SpiceRect r;
r.left = rects[i].x1;
r.top = rects[i].y1;
r.right = rects[i].x2;
r.bottom = rects[i].y2;
dc.fill_rect(r, 0);
}
}
void RedScreen::reset_mouse_pos()
{
_window.set_mouse_position(_mouse_anchor_point.x, _mouse_anchor_point.y);
}
void RedScreen::capture_mouse()
{
if (_mouse_captured || !_window.get_mouse_anchor_point(_mouse_anchor_point)) {
return;
}
if (_pointer_layer) {
_pointer_layer->on_pointer_leave();
_pointer_layer = NULL;
}
_pointer_on_screen = false;
_mouse_captured = true;
_window.hide_cursor();
reset_mouse_pos();
_window.capture_mouse();
}
void RedScreen::relase_mouse()
{
if (!_mouse_captured) {
return;
}
_mouse_captured = false;
_window.release_mouse();
update_pointer_layer();
}
void RedScreen::set_cursor(LocalCursor* cursor)
{
if (_mouse_captured) {
return;
}
_window.set_cursor(cursor);
}
void RedScreen::hide_cursor()
{
_window.hide_cursor();
}
ScreenLayer* RedScreen::find_pointer_layer()
{
for (int i = _layers.size() - 1; i >= 0; i--) {
ScreenLayer* layer;
if (!(layer = _layers[i])) {
continue;
}
if (layer->pointer_test(_pointer_pos.x, _pointer_pos.y)) {
return layer;
}
}
return NULL;
}
bool RedScreen::update_pointer_layer()
{
ASSERT(!_mouse_captured);
ScreenLayer* now = find_pointer_layer();
if (now == _pointer_layer) {
return false;
}
if (_pointer_layer) {
_pointer_layer->on_pointer_leave();
}
_pointer_layer = find_pointer_layer();
if (_pointer_layer) {
_pointer_layer->on_pointer_enter(_pointer_pos.x, _pointer_pos.y, _mouse_botton_state);
} else {
set_cursor(_inactive_cursor);
}
return true;
}
void RedScreen::on_pointer_enter(int x, int y, unsigned int buttons_state)
{
if (_mouse_captured) {
return;
}
_pointer_on_screen = true;
_pointer_pos.x = x;
_pointer_pos.y = y;
_mouse_botton_state = buttons_state;
ScreenLayer* layer = find_pointer_layer();
if (!layer) {
set_cursor(_inactive_cursor);
return;
}
_pointer_layer = layer;
_pointer_layer->on_pointer_enter(_pointer_pos.x, _pointer_pos.y, buttons_state);
if (_full_screen) {
/* allowing enterance to key interception mode without
requiring the user to press the window
*/
activate();
}
}
void RedScreen::on_mouse_motion(int x, int y, unsigned int buttons_state)
{
if (x != _mouse_anchor_point.x || y != _mouse_anchor_point.y) {
_owner.on_mouse_motion(x - _mouse_anchor_point.x,
y - _mouse_anchor_point.y,
buttons_state);
reset_mouse_pos();
}
}
void RedScreen::on_pointer_motion(int x, int y, unsigned int buttons_state)
{
if (_mouse_captured) {
on_mouse_motion(x, y, buttons_state);
return;
}
_pointer_pos.x = x;
_pointer_pos.y = y;
_mouse_botton_state = buttons_state;
if (update_pointer_layer() || !_pointer_layer) {
return;
}
_pointer_layer->on_pointer_motion(x, y, buttons_state);
}
void RedScreen::on_mouse_button_press(SpiceMouseButton button, unsigned int buttons_state)
{
if (_mouse_captured) {
_owner.on_mouse_down(button, buttons_state);
return;
}
if (!_pointer_layer) {
return;
}
_pointer_layer->on_mouse_button_press(button, buttons_state);
}
void RedScreen::on_mouse_button_release(SpiceMouseButton button, unsigned int buttons_state)
{
if (_mouse_captured) {
_owner.on_mouse_up(button, buttons_state);
return;
}
if (!_pointer_layer) {
return;
}
_pointer_layer->on_mouse_button_release(button, buttons_state);
}
void RedScreen::on_pointer_leave()
{
// ASSERT(!_mouse_captured);
if (_pointer_layer) {
_pointer_layer->on_pointer_leave();
_pointer_layer = NULL;
}
_pointer_on_screen = false;
}
void RedScreen::on_key_press(RedKey key)
{
_owner.on_key_down(key);
}
void RedScreen::on_key_release(RedKey key)
{
_owner.on_key_up(key);
}
void RedScreen::on_char(uint32_t ch)
{
_owner.on_char(ch);
}
void RedScreen::on_deactivate()
{
relase_mouse();
_active = false;
_owner.on_deactivate_screen(this);
}
void RedScreen::on_activate()
{
_active = true;
_owner.on_activate_screen(this);
}
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()
{
_force_update_timer++;
activate_timer();
}
void RedScreen::exit_modal_loop()
{
ASSERT(_force_update_timer > 0)
_force_update_timer--;
}
void RedScreen::pre_migrate()
{
for (int i = 0; i < (int)_layers.size(); i++) {
if (!_layers[i]) {
continue;
}
_layers[i]->pre_migrate();
}
}
void RedScreen::post_migrate()
{
for (int i = 0; i < (int)_layers.size(); i++) {
if (!_layers[i]) {
continue;
}
_layers[i]->post_migrate();
}
}
void RedScreen::exit_full_screen()
{
if (!_full_screen) {
return;
}
RecurciveLock lock(_update_lock);
_window.hide();
region_clear(&_dirty_region);
_window.set_type(RedWindow::TYPE_NORMAL);
adjust_window_rect(_save_pos.x, _save_pos.y);
_origin.x = _origin.y = 0;
_window.set_origin(0, 0);
show();
if (_menu_needs_update) {
update_menu();
}
_full_screen = false;
_out_of_sync = false;
_frame_area = false;
}
void RedScreen::save_position()
{
_save_pos = _window.get_position();
}
void RedScreen::__show_full_screen()
{
if (!_monitor) {
hide();
return;
}
SpicePoint position = _monitor->get_position();
SpicePoint monitor_size = _monitor->get_size();
_frame_area = false;
region_clear(&_dirty_region);
_window.set_type(RedWindow::TYPE_FULLSCREEN);
_window.move_and_resize(position.x, position.y, monitor_size.x, monitor_size.y);
if (!(_out_of_sync = _monitor->is_out_of_sync())) {
ASSERT(monitor_size.x >= _size.x);
ASSERT(monitor_size.y >= _size.y);
_origin.x = (monitor_size.x - _size.x) / 2;
_origin.y = (monitor_size.y - _size.y) / 2;
_frame_area = monitor_size.x != _size.x || monitor_size.y != _size.y;
} else {
_origin.x = _origin.y = 0;
}
_window.set_origin(_origin.x, _origin.y);
show();
}
void RedScreen::show_full_screen()
{
if (_full_screen) {
return;
}
RecurciveLock lock(_update_lock);
#ifndef WIN32
/* performing hide during resolution changes resulted in
missing WM_KEYUP events */
hide();
#endif
save_position();
_full_screen = true;
__show_full_screen();
}
void RedScreen::minimize()
{
_window.minimize();
}
void RedScreen::position_full_screen(const SpicePoint& position)
{
if (!_full_screen) {
return;
}
_window.move(position.x, position.y);
}
void RedScreen::hide()
{
_window.hide();
}
void RedScreen::show()
{
RecurciveLock lock(_update_lock);
_window.show(_monitor ? _monitor->get_screen_id() : 0);
}
void RedScreen::activate()
{
_window.activate();
}
void RedScreen::external_show()
{
DBG(0, "Entry");
_window.external_show();
}
void RedScreen::update_menu()
{
AutoRef<Menu> menu(_owner.get_app_menu());
int ret = _window.set_menu(*menu);
_menu_needs_update = (ret != 0); /* try again if menu update failed */
}
void RedScreen::on_exposed_rect(const SpiceRect& area)
{
if (is_out_of_sync()) {
_window.fill_rect(area, rgb32_make(0xff, 0xff, 0xff));
return;
}
invalidate(area, false);
}
int RedScreen::get_screen_id()
{
return _monitor ? _monitor->get_screen_id() : 0;
}
#ifdef USE_OPENGL
void RedScreen::untouch_context()
{
_window.untouch_context();
}
bool RedScreen::need_recreate_context_gl()
{
if (_full_screen) {
return true;
}
return false;
}
#endif
void RedScreen::set_update_interrupt_trigger(EventSources::Trigger *trigger)
{
_update_interrupt_trigger = trigger;
}
bool RedScreen::update_by_interrupt()
{
return _update_interrupt_trigger != NULL;
}
void RedScreen::interrupt_update()
{
_update_interrupt_trigger->trigger();
}
#ifdef USE_OPENGL
void RedScreen::set_type_gl()
{
_window.set_type_gl();
}
void RedScreen::unset_type_gl()
{
_window.unset_type_gl();
}
#endif // USE_OPENGL

View File

@ -1,211 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_SCREEN
#define _H_SCREEN
#include "common/region.h"
#include "common.h"
#include "red_key.h"
#ifdef USE_OPENGL
#include "GL/gl.h"
#endif // USE_OPENGL
#include "red_window.h"
#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,
SCREEN_LAYER_CURSOR,
SCREEN_LAYER_GUI_BARIER,
SCREEN_LAYER_GUI,
SCREEN_LAYER_INFO,
};
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::string& name, int width, int height);
RedScreen* ref();
void unref();
void attach_layer(ScreenLayer& layer);
void detach_layer(ScreenLayer& layer);
void on_layer_changed(ScreenLayer& layer);
/* When resizing on full screen mode, the monitor must be configured
* correctly before calling resize*/
void resize(int width, int height);
void set_name(const std::string& name);
uint64_t invalidate(const SpiceRect& rect, bool urgent);
void invalidate(const QRegion &region);
void capture_mouse();
void relase_mouse();
bool is_mouse_captured() { return _mouse_captured;}
bool intercepts_sys_key() { return _key_interception;}
SpicePoint 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;}
bool is_out_of_sync() { return _out_of_sync;}
void set_cursor(LocalCursor* cursor);
void hide_cursor();
void exit_full_screen();
void minimize();
void show(bool activate, RedScreen* pos);
void show_full_screen();
void position_full_screen(const SpicePoint& position);
void hide();
void show();
void activate();
void external_show();
void update_menu();
int get_id() { return _id;}
int get_screen_id();
#ifdef USE_OPENGL
void untouch_context();
bool need_recreate_context_gl();
void set_type_gl();
void unset_type_gl();
#endif
void set_update_interrupt_trigger(EventSources::Trigger *trigger);
bool update_by_interrupt();
void interrupt_update();
void update();
private:
friend class UpdateEvent;
friend class UpdateTimer;
virtual ~RedScreen();
void create_composit_area();
void destroy_composit_area();
void erase_background(RedDrawable& dc, const QRegion& region);
void notify_new_size();
void adjust_window_rect(int x, int y);
void save_position();
void __show_full_screen();
bool _invalidate(const SpiceRect& rect, bool urgent, uint64_t& update_mark);
void begin_update(QRegion& direct_rgn, QRegion& composit_rgn, QRegion& frame_rgn);
void update_composit(QRegion& composit_rgn);
void draw_direct(RedDrawable& win_dc, QRegion& direct_rgn, QRegion& composit_rgn,
QRegion& frame_rgn);
void activate_timer();
void update_done();
void periodic_update();
bool is_dirty() {return !region_is_empty(&_dirty_region);}
void composit_to_screen(RedDrawable& win_dc, const QRegion& region);
void reset_mouse_pos();
ScreenLayer* find_pointer_layer();
bool update_pointer_layer();
virtual void on_exposed_rect(const SpiceRect& area);
virtual void on_pointer_enter(int x, int y, unsigned int buttons_state);
virtual void on_pointer_motion(int x, int y, unsigned int buttons_state);
virtual void on_pointer_leave();
void on_mouse_motion(int x, int y, unsigned int buttons_state);
virtual void on_mouse_button_press(SpiceMouseButton button, unsigned int buttons_state);
virtual void on_mouse_button_release(SpiceMouseButton button, unsigned int buttons_state);
virtual void on_key_press(RedKey key);
virtual void on_key_release(RedKey key);
virtual void on_char(uint32_t ch);
virtual void on_deactivate();
virtual void on_activate();
virtual void on_start_key_interception();
virtual void on_stop_key_interception();
virtual void enter_modal_loop();
virtual void exit_modal_loop();
virtual void pre_migrate();
virtual void post_migrate();
private:
Application& _owner;
int _id;
AtomicCount _refs;
std::string _name;
RedWindow _window;
std::vector<ScreenLayer*> _layers;
QRegion _dirty_region;
RecurciveMutex _update_lock;
bool _active;
bool _full_screen;
bool _out_of_sync;
bool _frame_area;
bool _periodic_update;
bool _key_interception;
bool _update_by_timer;
bool _size_locked;
bool _menu_needs_update;
int _force_update_timer;
AutoRef<UpdateTimer> _update_timer;
RedDrawable* _composit_area;
uint64_t _update_mark;
SpicePoint _size;
SpicePoint _origin;
SpicePoint _mouse_anchor_point;
SpicePoint _save_pos;
Monitor* _monitor;
LocalCursor* _default_cursor;
LocalCursor* _inactive_cursor;
int _pixel_format_index;
EventSources::Trigger *_update_interrupt_trigger;
ScreenLayer* _pointer_layer;
bool _mouse_captured;
Mutex _layer_changed_lock;
bool _active_layer_change_event;
bool _pointer_on_screen;
SpicePoint _pointer_pos;
unsigned int _mouse_botton_state;
friend class LayerChangedEvent;
};
#endif

View File

@ -1,239 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "common.h"
#include "screen_layer.h"
#include "utils.h"
#include "screen.h"
#include "application.h"
#include "debug.h"
class AttachLayerEvent: public SyncEvent {
public:
AttachLayerEvent(ScreenLayer& layer, int screen_id)
: _layer (layer)
, _screen_id (screen_id)
{
}
virtual void do_response(AbstractProcessLoop& events_loop);
private:
ScreenLayer& _layer;
int _screen_id;
};
void AttachLayerEvent::do_response(AbstractProcessLoop& events_loop)
{
Application* app = (Application*)(events_loop.get_owner());
AutoRef<RedScreen> screen(app->get_screen(_screen_id));
(*screen)->attach_layer(_layer);
}
class DetachLayerEvent: public SyncEvent {
public:
DetachLayerEvent(ScreenLayer& _layer) : _layer (_layer) {}
virtual void do_response(AbstractProcessLoop& events_loop);
private:
ScreenLayer& _layer;
};
void DetachLayerEvent::do_response(AbstractProcessLoop& events_loop)
{
_layer.screen()->detach_layer(_layer);
}
ScreenLayer::ScreenLayer(int z_order, bool opaque)
: _screen (NULL)
, _z_order (z_order)
, _opaque (opaque)
, _using_ogl (false)
{
region_init(&_area);
region_init(&_direct_area);
region_init(&_composit_area);
}
ScreenLayer::~ScreenLayer()
{
ASSERT(!_screen);
region_destroy(&_area);
region_destroy(&_direct_area);
region_destroy(&_composit_area);
}
uint64_t ScreenLayer::invalidate_rect(const SpiceRect& r, bool urgent)
{
return _screen->invalidate(r, urgent);
}
uint64_t ScreenLayer::invalidate(const SpiceRect& r, bool urgent)
{
if (!_screen) {
return 0;
}
return invalidate_rect(r, urgent);
}
void ScreenLayer::invalidate(const QRegion& region)
{
pixman_box32_t *rects, *end;
int num_rects;
if (!_screen) {
return;
}
rects = pixman_region32_rectangles((pixman_region32_t *)&region, &num_rects);
end = rects + num_rects;
while (rects != end) {
SpiceRect r;
r.left = rects->x1;
r.top = rects->y1;
r.right = rects->x2;
r.bottom = rects->y2;
rects++;
invalidate_rect(r, false);
}
}
void ScreenLayer::invalidate()
{
invalidate(_area);
}
void ScreenLayer::notify_changed()
{
if (_screen) {
_screen->on_layer_changed(*this);
}
}
void ScreenLayer::set_area(const QRegion& area)
{
Lock lock(_area_lock);
invalidate();
region_destroy(&_area);
region_clone(&_area, &area);
invalidate();
notify_changed();
}
void ScreenLayer::clear_area()
{
Lock lock(_area_lock);
invalidate();
region_clear(&_area);
notify_changed();
}
void ScreenLayer::set_rect_area(const SpiceRect& r)
{
Lock lock(_area_lock);
invalidate();
region_clear(&_area);
region_add(&_area, &r);
invalidate();
notify_changed();
}
void ScreenLayer::offset_area(int dx, int dy)
{
Lock lock(_area_lock);
invalidate();
region_offset(&_area, dx, dy);
invalidate();
notify_changed();
}
void ScreenLayer::add_rect_area(const SpiceRect& r)
{
Lock lock(_area_lock);
region_add(&_area, &r);
notify_changed();
}
void ScreenLayer::remove_rect_area(const SpiceRect& r)
{
Lock lock(_area_lock);
invalidate();
region_remove(&_area, &r);
notify_changed();
}
void ScreenLayer::begin_update(QRegion& direct_rgn, QRegion& composit_rgn)
{
Lock lock(_area_lock);
region_destroy(&_direct_area);
region_clone(&_direct_area, &_area);
region_and(&_direct_area, &direct_rgn);
region_destroy(&_composit_area);
region_clone(&_composit_area, &_area);
region_and(&_composit_area, &composit_rgn);
region_exclude(&direct_rgn, &_direct_area);
if (_opaque) {
region_exclude(&composit_rgn, &_composit_area);
} else {
region_or(&composit_rgn, &_direct_area);
region_or(&_composit_area, &_direct_area);
region_clear(&_direct_area);
}
}
bool ScreenLayer::contains_point(int x, int y)
{
Lock lock(_area_lock);
return !!region_contains_point(&_area, x, y);
}
void ScreenLayer::attach_to_screen(Application& application, int screen_id)
{
if (_screen) {
return;
}
AutoRef<AttachLayerEvent> event(new AttachLayerEvent(*this, screen_id));
application.push_event(*event);
(*event)->wait();
if (!(*event)->success()) {
THROW("attach failed");
}
ASSERT(_screen);
}
void ScreenLayer::detach_from_screen(Application& application)
{
if (!_screen) {
return;
}
AutoRef<DetachLayerEvent> event(new DetachLayerEvent(*this));
application.push_event(*event);
(*event)->wait();
if (!(*event)->success()) {
THROW("detach failed");
}
ASSERT(!_screen);
}

View File

@ -1,87 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_SCREEN_LAYER
#define _H_SCREEN_LAYER
#include "common/region.h"
#include "threads.h"
class RedScreen;
class Application;
class ScreenLayer {
public:
ScreenLayer(int z_order, bool opaque);
virtual ~ScreenLayer();
void attach_to_screen(Application& application, int screen_id);
void detach_from_screen(Application& application);
void set_screen(RedScreen* screen) { _screen = screen;}
RedScreen* screen() { return _screen; }
int z_order() { return _z_order;}
void set_area(const QRegion& area);
void offset_area(int dx, int dy);
void clear_area();
void set_rect_area(const SpiceRect& r);
void add_rect_area(const SpiceRect& r);
void remove_rect_area(const SpiceRect& r);
void begin_update(QRegion& direct_rgn, QRegion& composit_rgn);
void invalidate();
uint64_t invalidate(const SpiceRect& r, bool urgent = false);
void invalidate(const QRegion& r);
bool contains_point(int x, int y);
virtual void copy_pixels(const QRegion& dest_region, RedDrawable& dest_dc) {}
void set_using_ogl(bool val) {_using_ogl = val;}
bool using_ogl() {return _using_ogl;}
virtual void on_size_changed() {}
virtual void pre_migrate() { }
virtual void post_migrate() { }
QRegion& area() { return _area;}
QRegion& direct_area() { return _direct_area;}
QRegion& composit_area() { return _composit_area;}
virtual void on_update_completion(uint64_t mark) {}
virtual bool pointer_test(int x, int y) { return false;}
virtual void on_pointer_enter(int x, int y, unsigned int buttons_state) {}
virtual void on_pointer_motion(int x, int y, unsigned int buttons_state) {}
virtual void on_pointer_leave() {}
virtual void on_mouse_button_press(int button, int buttons_state) {}
virtual void on_mouse_button_release(int button, int buttons_state) {}
private:
uint64_t invalidate_rect(const SpiceRect& r, bool urgent);
void notify_changed();
private:
RedScreen* _screen;
int _z_order;
bool _opaque;
bool _using_ogl;
Mutex _area_lock;
QRegion _area;
QRegion _direct_area;
QRegion _composit_area;
};
#endif

View File

@ -1,223 +0,0 @@
/*
Copyright (C) 2009 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _H_SHARED_CACHE
#define _H_SHARED_CACHE
#include "utils.h"
#include "threads.h"
/*class SharedCache::Treat {
T* get(T*);
void release(T*);
const char* name();
};*/
template <class T, class Treat, int HASH_SIZE, class Base = EmptyBase>
class SharedCache : public Base {
public:
SharedCache()
: _aborting (false)
{
memset(_hash, 0, sizeof(_hash));
}
~SharedCache()
{
clear();
}
void add(uint64_t id, T* data, bool is_lossy = FALSE)
{
Lock lock(_lock);
Item** item = &_hash[key(id)];
while (*item) {
if ((*item)->id == id) {
(*item)->refs++;
return;
}
item = &(*item)->next;
}
*item = new Item(id, data, is_lossy);
_new_item_cond.notify_all();
}
T* get(uint64_t id)
{
Lock lock(_lock);
Item* item = _hash[key(id)];
for (;;) {
if (!item) {
if (_aborting) {
THROW("%s aborting", Treat::name());
}
_new_item_cond.wait(lock);
item = _hash[key(id)];
continue;
}
if (item->id != id) {
item = item->next;
continue;
}
return Treat::get(item->data);
}
}
T* get_lossless(uint64_t id)
{
Lock lock(_lock);
Item* item = _hash[key(id)];
for (;;) {
if (!item) {
if (_aborting) {
THROW("%s aborting", Treat::name());
}
_new_item_cond.wait(lock);
item = _hash[key(id)];
continue;
}
if (item->id != id) {
item = item->next;
continue;
}
break;
}
// item has been retreived. Now checking if lossless
for (;;) {
if (item->lossy) {
if (_aborting) {
THROW("%s aborting", Treat::name());
}
_replace_data_cond.wait(lock);
continue;
}
return Treat::get(item->data);
}
}
void replace(uint64_t id, T* data, bool is_lossy = FALSE)
{
Lock lock(_lock);
Item* item = _hash[key(id)];
for (;;) {
if (!item) {
if (_aborting) {
THROW("%s aborting", Treat::name());
}
_new_item_cond.wait(lock);
item = _hash[key(id)];
continue;
}
if (item->id != id) {
item = item->next;
continue;
}
item->replace(data, is_lossy);
break;
}
_replace_data_cond.notify_all();
}
void remove(uint64_t id)
{
Lock lock(_lock);
Item** item = &_hash[key(id)];
while (*item) {
if ((*item)->id == id) {
if (!--(*item)->refs) {
Item *rm_item = *item;
*item = rm_item->next;
delete rm_item;
}
return;
}
item = &(*item)->next;
}
THROW("%s id %" PRIu64 ", not found", Treat::name(), id);
}
void clear()
{
Lock lock(_lock);
for (int i = 0; i < HASH_SIZE; i++) {
while (_hash[i]) {
Item *item = _hash[i];
_hash[i] = item->next;
delete item;
}
}
}
void abort()
{
Lock lock(_lock);
_aborting = true;
_new_item_cond.notify_all();
}
private:
inline uint32_t key(uint64_t id) {return uint32_t(id) % HASH_SIZE;}
private:
class Item {
public:
Item(uint64_t in_id, T* data, bool is_lossy = FALSE)
: id (in_id)
, refs (1)
, next (NULL)
, data (Treat::get(data))
, lossy (is_lossy) {}
~Item()
{
Treat::release(data);
}
void replace(T* new_data, bool is_lossy = FALSE)
{
Treat::release(data);
data = Treat::get(new_data);
lossy = is_lossy;
}
uint64_t id;
int refs;
Item* next;
T* data;
bool lossy;
};
Item* _hash[HASH_SIZE];
Mutex _lock;
Condition _new_item_cond;
Condition _replace_data_cond;
bool _aborting;
};
#endif

View File

@ -1,553 +0,0 @@
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <spice/enums.h>
#include "common/mutex.h"
#include "red_client.h"
extern "C" {
#include <vscard_common.h>
#include <vreader.h>
#include <vcard_emul.h>
#include <vevent.h>
}
#include "smartcard_channel.h"
#define APDUBufSize 270
#define MAX_ATR_LEN 40
//#define DEBUG_SMARTCARD
#ifdef DEBUG_SMARTCARD
void PrintByteArray(uint8_t *arrBytes, unsigned int nSize)
{
int i;
for (i=0; i < nSize; i++) {
DBG(0, "%X ", arrBytes[i]);
}
DBG(0, "\n");
}
#define DEBUG_PRINT_BYTE_ARRAY(arrBytes, nSize) PrintByteArray(arrBytes, nSize)
#else
#define DEBUG_PRINT_BYTE_ARRAY(arrBytes, nSize)
#endif
SmartCardChannel* g_smartcard_channel = NULL; // used for insert/remove of virtual card. Can be
// changed if we let Application store the SmartCard instance.
class SmartCardHandler: public MessageHandlerImp<SmartCardChannel, SPICE_CHANNEL_SMARTCARD> {
public:
SmartCardHandler(SmartCardChannel& channel)
: MessageHandlerImp<SmartCardChannel, SPICE_CHANNEL_SMARTCARD>(channel) {}
};
SmartCardChannel::SmartCardChannel(RedClient& client, uint32_t id)
: RedChannel(client, SPICE_CHANNEL_SMARTCARD, id, new SmartCardHandler(*this))
, _next_sync_vevent(VEVENT_LAST)
{
SmartCardHandler* handler = static_cast<SmartCardHandler*>(get_message_handler());
g_smartcard_channel = this;
handler->set_handler(SPICE_MSG_SMARTCARD_DATA,
&SmartCardChannel::handle_smartcard_data);
}
ReaderData* SmartCardChannel::reader_data_from_vreader(VReader* vreader)
{
if (vreader == NULL) {
assert(_readers_by_vreader.size() > 0);
return _readers_by_vreader.begin()->second;
}
if (_readers_by_vreader.count(vreader) > 0) {
return _readers_by_vreader.find(vreader)->second;
}
assert(_unallocated_readers_by_vreader.count(vreader) > 0);
return _unallocated_readers_by_vreader.find(vreader)->second;
}
ReaderData* SmartCardChannel::reader_data_from_reader_id(uint32_t reader_id)
{
if (_readers_by_id.count(reader_id) > 0) {
return _readers_by_id.find(reader_id)->second;
}
return NULL;
}
/** On VEVENT_READER_INSERT we call this, send a VSC_ReaderAdd, and wait for a VSC_ReaderAddResponse
*/
void SmartCardChannel::add_unallocated_reader(VReader* vreader, const char* name)
{
ReaderData* data = new ReaderData();
data->vreader = vreader;
data->reader_id = VSCARD_UNDEFINED_READER_ID;
data->name = spice_strdup(name);
_unallocated_readers_by_vreader.insert(std::pair<VReader*, ReaderData*>(vreader, data));
LOG_INFO("adding unallocated reader %p", data);
}
/** called upon the VSC_ReaderAddResponse
*/
ReaderData* SmartCardChannel::add_reader(uint32_t reader_id)
{
ReaderData* data;
size_t unallocated = _unallocated_readers_by_vreader.size();
assert(unallocated > 0);
data = _unallocated_readers_by_vreader.begin()->second;
data->reader_id = reader_id;
LOG_INFO("adding %p->%d", data, reader_id);
_readers_by_vreader.insert(
std::pair<VReader*, ReaderData*>(data->vreader, data));
assert(_readers_by_vreader.count(data->vreader) == 1);
_readers_by_id.insert(std::pair<uint32_t, ReaderData*>(reader_id, data));
assert(_readers_by_id.count(reader_id) == 1);
_unallocated_readers_by_vreader.erase(_unallocated_readers_by_vreader.begin());
assert(_unallocated_readers_by_vreader.size() == unallocated - 1);
assert(_unallocated_readers_by_vreader.count(data->vreader) == 0);
return data;
}
void* SmartCardChannel::cac_card_events_thread_entry(void* data)
{
static_cast<SmartCardChannel*>(data)->cac_card_events_thread_main();
return NULL;
}
VEventEvent::VEventEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
: _smartcard_channel(smartcard_channel)
, _vreader(vevent->reader)
, _vevent(vevent)
{
}
VEventEvent::~VEventEvent()
{
vevent_delete(_vevent);
}
void ReaderAddEvent::response(AbstractProcessLoop& events_loop)
{
static int num = 0;
char name[20];
sprintf(name, "test%4d", num++);
_smartcard_channel->add_unallocated_reader(_vreader, name);
_smartcard_channel->send_reader_added(name);
}
void ReaderRemoveEvent::response(AbstractProcessLoop& events_loop)
{
ReaderData* data;
data = _smartcard_channel->reader_data_from_vreader(_vreader);
_smartcard_channel->send_reader_removed(data->reader_id);
_smartcard_channel->remove_reader(data);
}
void CardInsertEvent::response(AbstractProcessLoop& events_loop)
{
ReaderData* data = _smartcard_channel->reader_data_from_vreader(
_vreader);
if (data->reader_id == VSCARD_UNDEFINED_READER_ID) {
data->card_insert_pending = true;
} else {
_smartcard_channel->send_atr(_vreader);
}
}
void CardRemoveEvent::response(AbstractProcessLoop& events_loop)
{
ReaderData* data = _smartcard_channel->reader_data_from_vreader(
_vreader);
ASSERT(data->reader_id != VSCARD_UNDEFINED_READER_ID);
_smartcard_channel->send_message(data->reader_id, VSC_CardRemove, NULL, 0);
}
void SmartCardChannel::remove_reader(ReaderData* data)
{
// TODO - untested code (caccard doesn't produce these events yet)
if (_readers_by_vreader.count(data->vreader) > 0) {
_readers_by_vreader.erase(_readers_by_vreader.find(data->vreader));
_readers_by_id.erase(_readers_by_id.find(data->reader_id));
} else {
_unallocated_readers_by_vreader.erase(
_unallocated_readers_by_vreader.find(data->vreader));
}
free(data->name);
delete data;
}
/* Sync events need to be sent one by one, waiting for VSC_Error
* messages from the server in between. */
void SmartCardChannel::push_sync_event(VEventType type, Event *event)
{
event->ref();
_sync_events.push_back(SmartCardEvent(type, event));
if (_next_sync_vevent != VEVENT_LAST) {
return;
}
send_next_sync_event();
}
void SmartCardChannel::send_next_sync_event()
{
if (_sync_events.empty()) {
_next_sync_vevent = VEVENT_LAST;
return;
}
SmartCardEvent sync_event = _sync_events.front();
_sync_events.pop_front();
get_client().push_event(sync_event.second);
sync_event.second->unref();
_next_sync_vevent = sync_event.first;
}
void SmartCardChannel::handle_reader_add_response(VSCMsgHeader *vheader,
VSCMsgError *error)
{
ReaderData* data;
if (error->code == VSC_SUCCESS) {
data = add_reader(vheader->reader_id);
if (data->card_insert_pending) {
data->card_insert_pending = false;
send_atr(data->vreader);
}
} else {
LOG_WARN("VSC Error: reader %d, code %d",
vheader->reader_id, error->code);
}
}
void SmartCardChannel::handle_error_message(VSCMsgHeader *vheader,
VSCMsgError *error)
{
switch (_next_sync_vevent) {
case VEVENT_READER_INSERT:
handle_reader_add_response(vheader, error);
break;
case VEVENT_CARD_INSERT:
case VEVENT_CARD_REMOVE:
case VEVENT_READER_REMOVE:
break;
default:
LOG_WARN("Unexpected Error message: %d", error->code);
}
send_next_sync_event();
}
void SmartCardChannel::cac_card_events_thread_main()
{
VEvent *vevent = NULL;
bool cont = true;
while (cont) {
vevent = vevent_wait_next_vevent();
if (vevent == NULL) {
break;
}
switch (vevent->type) {
case VEVENT_READER_INSERT:
LOG_INFO("VEVENT_READER_INSERT");
{
AutoRef<ReaderAddEvent> event(new ReaderAddEvent(this, vevent));
push_sync_event(vevent->type, *event);
}
break;
case VEVENT_READER_REMOVE:
LOG_INFO("VEVENT_READER_REMOVE");
{
AutoRef<ReaderRemoveEvent> event(new ReaderRemoveEvent(this, vevent));
push_sync_event(vevent->type, *event);
}
break;
case VEVENT_CARD_INSERT:
LOG_INFO("VEVENT_CARD_INSERT");
{
AutoRef<CardInsertEvent> event(new CardInsertEvent(this, vevent));
push_sync_event(vevent->type, *event);
}
break;
case VEVENT_CARD_REMOVE:
LOG_INFO("VEVENT_CARD_REMOVE");
{
AutoRef<CardRemoveEvent> event(new CardRemoveEvent(this, vevent));
push_sync_event(vevent->type, *event);
}
break;
case VEVENT_LAST:
cont = false;
default:
/* anything except VEVENT_LAST and default
* gets to VEventEvent which does vevent_delete in VEventEvent~ */
vevent_delete(vevent);
}
}
}
void virtual_card_insert()
{
if (g_smartcard_channel == NULL) {
return;
}
g_smartcard_channel->virtual_card_insert();
}
void SmartCardChannel::virtual_card_insert()
{
if (_readers_by_id.size() == 0) {
return;
}
vcard_emul_force_card_insert(_readers_by_id.begin()->second->vreader);
}
void virtual_card_remove()
{
if (g_smartcard_channel == NULL) {
return;
}
g_smartcard_channel->virtual_card_remove();
}
void SmartCardChannel::virtual_card_remove()
{
if (_readers_by_id.size() == 0) {
return;
}
vcard_emul_force_card_remove(_readers_by_id.begin()->second->vreader);
}
#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
#define CERTIFICATES_ARGS_TEMPLATE "db=\"%s\" use_hw=no soft=(,Virtual Card,CAC,,%s,%s,%s)"
SmartcardOptions::SmartcardOptions() :
dbname(CERTIFICATES_DEFAULT_DB),
enable(false)
{
}
static VCardEmulError init_vcard_local_certs(const char* dbname, const char* cert1,
const char* cert2, const char* cert3)
{
char emul_args[200];
VCardEmulOptions *options = NULL;
snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
dbname, cert1, cert2, cert3);
options = vcard_emul_options(emul_args);
if (options == NULL) {
LOG_WARN("not using certificates due to initialization error");
}
return vcard_emul_init(options);
}
static bool g_vcard_inited = false;
void smartcard_init(const SmartcardOptions* options)
{
if (g_vcard_inited) {
return;
}
if (options->certs.size() == 3) {
const char* dbname = options->dbname.c_str();
if (init_vcard_local_certs(dbname, options->certs[0].c_str(),
options->certs[1].c_str(), options->certs[2].c_str()) != VCARD_EMUL_OK) {
throw Exception("smartcard: emulated card initialization failed (check certs/db)");
}
} else {
if (options->certs.size() > 0) {
LOG_WARN("Ignoring smartcard certificates - must be exactly three for virtual card emulation");
}
if (vcard_emul_init(NULL) != VCARD_EMUL_OK) {
throw Exception("smartcard: vcard initialization failed (check hardware/drivers)");
}
}
g_vcard_inited = true;
}
void SmartCardChannel::on_connect()
{
_event_thread = new Thread(SmartCardChannel::cac_card_events_thread_entry, this);
}
void SmartCardChannel::on_disconnect()
{
VEvent *stop_event;
if (_event_thread == NULL) {
return;
}
stop_event = vevent_new(VEVENT_LAST, NULL, NULL);
vevent_queue_vevent(stop_event);
_event_thread->join();
delete _event_thread;
_event_thread = NULL;
}
void SmartCardChannel::send_reader_removed(uint32_t reader_id)
{
send_message(reader_id, VSC_ReaderRemove, NULL, 0);
}
void SmartCardChannel::send_reader_added(const char* reader_name)
{
send_message(VSCARD_UNDEFINED_READER_ID,
VSC_ReaderAdd, (uint8_t*)reader_name, strlen(reader_name));
}
void SmartCardChannel::send_atr(VReader* vreader)
{
unsigned char atr[ MAX_ATR_LEN];
int atr_len = MAX_ATR_LEN;
uint32_t reader_id = reader_data_from_vreader(vreader)->reader_id;
assert(reader_id != VSCARD_UNDEFINED_READER_ID);
vreader_power_on(vreader, atr, &atr_len);
DBG(0, "ATR: ");
DEBUG_PRINT_BYTE_ARRAY(atr, atr_len);
send_message(reader_id, VSC_ATR, (uint8_t*)atr, atr_len);
}
void SmartCardChannel::send_message(uint32_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len)
{
VSCMsgHeader mhHeader;
Message* msg = new Message(SPICE_MSGC_SMARTCARD_DATA);
SpiceMarshaller* m = msg->marshaller();
mhHeader.type = type;
mhHeader.length = len;
mhHeader.reader_id = reader_id;
spice_marshaller_add(m, (uint8_t*)&mhHeader, sizeof(mhHeader));
spice_marshaller_add(m, data, len);
post_message(msg);
}
VSCMessageEvent::VSCMessageEvent(SmartCardChannel* smartcard_channel,
VSCMsgHeader* vheader)
: _smartcard_channel(smartcard_channel)
, _vheader(NULL)
{
_vheader = (VSCMsgHeader*)spice_memdup(vheader,
sizeof(VSCMsgHeader) + vheader->length);
ASSERT(_vheader);
}
VSCMessageEvent::~VSCMessageEvent()
{
free(_vheader);
}
void VSCMessageEvent::response(AbstractProcessLoop& loop)
{
static int recv_count = 0;
int dwSendLength;
int dwRecvLength;
uint8_t* pbSendBuffer = _vheader->data;
uint8_t pbRecvBuffer[APDUBufSize+sizeof(uint32_t)];
VReaderStatus reader_status;
uint32_t rv;
switch (_vheader->type) {
case VSC_APDU:
break;
case VSC_Error:
_smartcard_channel->handle_error_message(
_vheader,
(VSCMsgError*)_vheader->data);
return;
case VSC_Init:
break;
default:
LOG_WARN("unhandled VSC %d of length %d, reader %d",
_vheader->type, _vheader->length, _vheader->reader_id);
return;
}
/* Transmit recieved APDU */
dwSendLength = _vheader->length;
dwRecvLength = sizeof(pbRecvBuffer);
DBG(0, " %3d: recv APDU: ", recv_count++);
DEBUG_PRINT_BYTE_ARRAY(pbSendBuffer, _vheader->length);
ReaderData* reader_data = _smartcard_channel->reader_data_from_reader_id(
_vheader->reader_id);
if (reader_data == NULL) {
LOG_WARN("got message for non existant reader");
return;
}
VReader* vreader = reader_data->vreader;
reader_status = vreader_xfr_bytes(vreader,
pbSendBuffer, dwSendLength,
pbRecvBuffer, &dwRecvLength);
if (reader_status == VREADER_OK) {
DBG(0, " sent APDU: ");
DEBUG_PRINT_BYTE_ARRAY(pbRecvBuffer, dwRecvLength);
_smartcard_channel->send_message (
_vheader->reader_id,
VSC_APDU,
pbRecvBuffer,
dwRecvLength
);
} else {
rv = reader_status; /* warning: not meaningful */
_smartcard_channel->send_message (
_vheader->reader_id,
VSC_Error,
(uint8_t*)&rv,
sizeof (uint32_t)
);
}
}
void SmartCardChannel::handle_smartcard_data(RedPeer::InMessage* message)
{
VSCMsgHeader* mhHeader = (VSCMsgHeader*)(message->data());
AutoRef<VSCMessageEvent> event(new VSCMessageEvent(this, mhHeader));
get_client().push_event(*event);
}
class SmartCardFactory: public ChannelFactory {
public:
SmartCardFactory() : ChannelFactory(SPICE_CHANNEL_SMARTCARD) {}
virtual RedChannel* construct(RedClient& client, uint32_t id)
{
return new SmartCardChannel(client, id);
}
};
static SmartCardFactory factory;
ChannelFactory& SmartCardChannel::Factory()
{
return factory;
}

View File

@ -1,159 +0,0 @@
/*
Copyright (C) 2010 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SMART_CARD_H__
#define __SMART_CARD_H__
#include <map>
#include <vreadert.h>
#include <vscard_common.h>
#include <eventt.h>
#include "red_channel.h"
#include "red_peer.h"
class Application;
struct SmartcardOptions {
std::vector<std::string> certs;
std::string dbname;
bool enable;
SmartcardOptions();
};
void smartcard_init(const SmartcardOptions* options);
struct ReaderData {
ReaderData() :
vreader(NULL),
reader_id(VSCARD_UNDEFINED_READER_ID),
name(NULL),
card_insert_pending(false)
{}
VReader *vreader;
uint32_t reader_id;
char* name;
bool card_insert_pending;
};
void virtual_card_remove();
void virtual_card_insert();
class SmartCardChannel;
class VEventEvent : public Event {
public:
VEventEvent(SmartCardChannel* smartcard_channel, VEvent* vevent);
~VEventEvent();
SmartCardChannel* _smartcard_channel;
VReader* _vreader;
VEvent* _vevent;
};
class ReaderAddEvent: public VEventEvent {
public:
ReaderAddEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
: VEventEvent(smartcard_channel, vevent) {}
virtual void response(AbstractProcessLoop& events_loop);
};
class ReaderRemoveEvent: public VEventEvent {
public:
ReaderRemoveEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
: VEventEvent(smartcard_channel, vevent) {}
virtual void response(AbstractProcessLoop& events_loop);
};
class CardInsertEvent: public VEventEvent {
public:
CardInsertEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
: VEventEvent(smartcard_channel, vevent) {}
virtual void response(AbstractProcessLoop& events_loop);
};
class CardRemoveEvent: public VEventEvent {
public:
CardRemoveEvent(SmartCardChannel* smartcard_channel, VEvent* vevent)
: VEventEvent(smartcard_channel, vevent) {}
virtual void response(AbstractProcessLoop& events_loop);
};
class VSCMessageEvent: public Event {
public:
VSCMessageEvent(SmartCardChannel* smartcard_channel,
VSCMsgHeader* vheader);
~VSCMessageEvent();
SmartCardChannel* _smartcard_channel;
VSCMsgHeader* _vheader;
virtual void response(AbstractProcessLoop& events_loop);
};
typedef std::pair<VEventType, Event*> SmartCardEvent;
class SmartCardChannel : public RedChannel {
public:
SmartCardChannel(RedClient& client, uint32_t id);
void handle_smartcard_data(RedPeer::InMessage* message);
void virtual_card_remove();
void virtual_card_insert();
static ChannelFactory& Factory();
protected:
virtual void on_connect();
virtual void on_disconnect();
private:
static void* cac_card_events_thread_entry(void* data);
void cac_card_events_thread_main();
void send_message(uint32_t reader_id, VSCMsgType type, uint8_t* data, uint32_t len);
Thread* _event_thread;
Application* _app;
VReaderList *_reader_list;
typedef std::map<uint32_t, ReaderData*> readers_by_id_t;
readers_by_id_t _readers_by_id;
typedef std::map<VReader*, ReaderData*> readers_by_vreader_t;
readers_by_vreader_t _readers_by_vreader;
readers_by_vreader_t _unallocated_readers_by_vreader;
VEventType _next_sync_vevent;
std::list<SmartCardEvent> _sync_events;
void push_sync_event(VEventType type, Event *event);
void send_next_sync_event();
void handle_reader_add_response(VSCMsgHeader *vheader, VSCMsgError *error);
void handle_error_message(VSCMsgHeader *vheader, VSCMsgError *error);
ReaderData* reader_data_from_vreader(VReader* vreader);
ReaderData* reader_data_from_reader_id(uint32_t reader_id);
void add_unallocated_reader(VReader* vreader, const char* name);
ReaderData* add_reader(uint32_t reader_id);
void remove_reader(ReaderData* data);
void send_reader_added(const char* reader_name);
void send_reader_removed(uint32_t reader_id);
void send_atr(VReader* vreader);
friend class ReaderAddEvent;
friend class ReaderRemoveEvent;
friend class CardInsertEvent;
friend class CardRemoveEvent;
friend class VSCMessageEvent;
};
#endif // __SMART_CARD_H__

Some files were not shown because too many files have changed in this diff Show More