[Spice-devel] [PATCH spice 8/9] spicec: add foreign menu
Hans de Goede
hdegoede at redhat.com
Mon Oct 18 01:40:51 PDT 2010
Ack.
On 10/18/2010 10:20 AM, Arnon Gilboa wrote:
> Spice foreign menu enables external control of the client menu.
>
> The foreignmenu protocol enables an external application to:
> add a submenu, set its title, clear it, add/modify/remove an item etc.
>
> Foreign menu is based on the cross-platform named pipe.
> ---
> client/Makefile.am | 2 +
> client/application.cpp | 74 +++++++++-
> client/application.h | 26 +++-
> client/foreign_menu.cpp | 364 ++++++++++++++++++++++++++++++++++++++++++++
> client/foreign_menu.h | 98 ++++++++++++
> client/windows/redc.vcproj | 18 ++-
> client/x11/Makefile.am | 2 +
> 7 files changed, 574 insertions(+), 10 deletions(-)
> create mode 100644 client/foreign_menu.cpp
> create mode 100644 client/foreign_menu.h
>
> diff --git a/client/Makefile.am b/client/Makefile.am
> index 185518a..09f11d5 100644
> --- a/client/Makefile.am
> +++ b/client/Makefile.am
> @@ -61,6 +61,8 @@ RED_COMMON_SRCS = \
> debug.h \
> display_channel.cpp \
> display_channel.h \
> + foreign_menu.cpp \
> + foreign_menu.h \
> glz_decoded_image.h \
> glz_decoder_config.h \
> glz_decoder.cpp \
> diff --git a/client/application.cpp b/client/application.cpp
> index c5d34ff..9a9a3f6 100644
> --- a/client/application.cpp
> +++ b/client/application.cpp
> @@ -335,6 +335,8 @@ enum AppCommands {
> #ifdef USE_GUI
> APP_CMD_SHOW_GUI,
> #endif // USE_GUI
> + APP_CMD_EXTERNAL_BEGIN = 0x400,
> + APP_CMD_EXTERNAL_END = 0x800,
> };
>
> Application::Application()
> @@ -586,6 +588,13 @@ void Application::switch_host(const std::string& host, int port, int sport,
>
> int Application::run()
> {
> + _exit_code = ProcessLoop::run();
> + return _exit_code;
> +}
> +
> +void Application::on_start_running()
> +{
> + _foreign_menu.reset(new ForeignMenu(this));
> #ifdef USE_GUI
> if (_gui_mode != GUI_MODE_FULL) {
> connect();
> @@ -595,8 +604,6 @@ int Application::run()
> #else
> connect();
> #endif // HAVE_GUI
> - _exit_code = ProcessLoop::run();
> - return _exit_code;
> }
>
> RedScreen* Application::find_screen(int id)
> @@ -974,6 +981,14 @@ void Application::do_command(int command)
> show_gui();
> break;
> #endif // USE_GUI
> + default:
> + AppMenuItemMap::iterator iter = _app_menu_items.find(command);
> + ASSERT(iter != _app_menu_items.end());
> + AppMenuItem* item =&(*iter).second;
> + if (item->type == APP_MENU_ITEM_TYPE_FOREIGN) {
> + ASSERT(*_foreign_menu);
> + (*_foreign_menu)->on_command(item->conn_ref, item->ext_id);
> + }
> }
> }
>
> @@ -1318,12 +1333,18 @@ void Application::on_app_activated()
> {
> _active = true;
> _key_handler->on_focus_in();
> + if (*_foreign_menu) {
> + (*_foreign_menu)->on_activate();
> + }
> }
>
> void Application::on_app_deactivated()
> {
> _active = false;
> _key_handler->on_focus_out();
> + if (*_foreign_menu) {
> + (*_foreign_menu)->on_deactivate();
> + }
> #ifdef WIN32
> if (!_changing_screens) {
> exit_full_screen();
> @@ -1573,7 +1594,7 @@ uint32_t Application::get_mouse_mode()
> return _client.get_mouse_mode();
> }
>
> -void Application::set_title(std::wstring& title)
> +void Application::set_title(const std::wstring& title)
> {
> _title = title;
>
> @@ -1665,6 +1686,53 @@ void Application::send_hotkey_key_set(const HotkeySet& key_set)
> }
> }
>
> +int Application::get_menu_item_id(AppMenuItemType type, int32_t conn_ref, uint32_t ext_id)
> +{
> + int free_id = APP_CMD_EXTERNAL_BEGIN;
> + AppMenuItem item = {type, conn_ref, ext_id};
> + AppMenuItemMap::iterator iter = _app_menu_items.begin();
> + for (; iter != _app_menu_items.end(); iter++) {
> + if (!memcmp(&(*iter).second,&item, sizeof(item))) {
> + return (*iter).first;
> + } else if (free_id == (*iter).first&& ++free_id> APP_CMD_EXTERNAL_END) {
> + return APP_CMD_INVALID;
> + }
> + }
> + _app_menu_items[free_id] = item;
> + return free_id;
> +}
> +
> +void Application::clear_menu_items(int32_t opaque_conn_ref)
> +{
> + AppMenuItemMap::iterator iter = _app_menu_items.begin();
> + AppMenuItemMap::iterator curr;
> +
> + while (iter != _app_menu_items.end()) {
> + curr = iter++;
> + if (((*curr).second).conn_ref == opaque_conn_ref) {
> + _app_menu_items.erase(curr);
> + }
> + }
> +}
> +
> +void Application::remove_menu_item(int item_id)
> +{
> + _app_menu_items.erase(item_id);
> +}
> +
> +int Application::get_foreign_menu_item_id(int32_t opaque_conn_ref, uint32_t msg_id)
> +{
> + return get_menu_item_id(APP_MENU_ITEM_TYPE_FOREIGN, opaque_conn_ref, msg_id);
> +}
> +
> +void Application::update_menu()
> +{
> + for (size_t i = 0; i< _screens.size(); ++i) {
> + if (_screens[i]) {
> + _screens[i]->update_menu();
> + }
> + }
> +}
>
> //controller interface begin
>
> diff --git a/client/application.h b/client/application.h
> index 36ae86e..d6355ca 100644
> --- a/client/application.h
> +++ b/client/application.h
> @@ -26,6 +26,7 @@
> #include "menu.h"
> #include "hot_keys.h"
> #include "process_loop.h"
> +#include "foreign_menu.h"
>
> class RedScreen;
> class Application;
> @@ -138,10 +139,23 @@ typedef std::list<KeyHandler*> KeyHandlersStack;
> typedef std::list<GUIBarrier*> GUIBarriers;
> #endif // USE_GUI
>
> +enum AppMenuItemType {
> + APP_MENU_ITEM_TYPE_INVALID,
> + APP_MENU_ITEM_TYPE_FOREIGN,
> +};
> +
> +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 CommandTarget {
> + public ForeignMenuInterface {
> public:
>
> enum State {
> @@ -186,6 +200,7 @@ public:
> 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();
> @@ -200,7 +215,7 @@ public:
> void exit_full_screen();
> bool toggle_full_screen();
> void minimize();
> - void set_title(std::wstring& title);
> + void set_title(const std::wstring& title);
> void hide();
> void show();
> void external_show();
> @@ -216,6 +231,10 @@ public:
> 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
> bool connect(const std::string& host, int port, int sport, const std::string& password);
> @@ -276,6 +295,7 @@ private:
> 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_commnad();
> bool is_key_set_pressed(const HotkeySet& key_set);
> void do_on_key_up(RedKey key);
> @@ -341,6 +361,8 @@ private:
> StickyInfo _sticky_info;
> std::vector<int> _canvas_types;
> AutoRef<Menu> _app_menu;
> + AutoRef<ForeignMenu> _foreign_menu;
> + AppMenuItemMap _app_menu_items;
> #ifdef USE_GUI
> std::auto_ptr<GUI> _gui;
> AutoRef<GUITimer> _gui_timer;
> diff --git a/client/foreign_menu.cpp b/client/foreign_menu.cpp
> new file mode 100644
> index 0000000..e5d7459
> --- /dev/null
> +++ b/client/foreign_menu.cpp
> @@ -0,0 +1,364 @@
> +/*
> + 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/>.
> +*/
> +
> +#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__)
> +#define PIPE_NAME "/tmp/SpiceForeignMenu-%llu.uds"
> +#else
> +#define PIPE_NAME "/tmp/SpiceForeignMenu-%lu.uds"
> +#endif
> +
> +ForeignMenu::ForeignMenu(ForeignMenuInterface *handler)
> + : _handler (handler)
> + , _active (false)
> + , _refs (1)
> +{
> + char pipe_name[PIPE_NAME_MAX_LEN];
> +
> + ASSERT(_handler != NULL);
> + 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) {
> + memcpy(_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;
> +}
> diff --git a/client/foreign_menu.h b/client/foreign_menu.h
> new file mode 100644
> index 0000000..2fc4e53
> --- /dev/null
> +++ b/client/foreign_menu.h
> @@ -0,0 +1,98 @@
> +/*
> + 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);
> + 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
> diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj
> index 6b5182c..538d2cb 100644
> --- a/client/windows/redc.vcproj
> +++ b/client/windows/redc.vcproj
> @@ -1,7 +1,7 @@
> <?xml version="1.0" encoding="windows-1255"?>
> <VisualStudioProject
> ProjectType="Visual C++"
> - Version="9,00"
> + Version="9.00"
> Name="redc"
> ProjectGUID="{4F03BAF9-DFBC-4CA7-B860-8929555981AE}"
> RootNamespace="redc"
> @@ -228,6 +228,10 @@
> >
> </File>
> <File
> + RelativePath="..\foreign_menu.cpp"
> + >
> + </File>
> + <File
> RelativePath="..\gdi_canvas.cpp"
> >
> </File>
> @@ -508,6 +512,10 @@
> >
> </File>
> <File
> + RelativePath="..\foreign_menu.h"
> + >
> + </File>
> + <File
> RelativePath="..\..\common\gdi_canvas.h"
> >
> </File>
> @@ -711,7 +719,7 @@
> <Tool
> Name="VCCustomBuildTool"
> Description="Generating demarshaller"
> - CommandLine="generate.bat"
> + CommandLine="generate.bat
"
> AdditionalDependencies=""
> Outputs="$(ProjectDir)/../generated_demarshallers.cpp;$(ProjectDir)/../generated_marshallers.cpp"
> />
> @@ -722,7 +730,7 @@
> <Tool
> Name="VCCustomBuildTool"
> Description="Generating demarshaller"
> - CommandLine="generate.bat"
> + CommandLine="generate.bat
"
> Outputs="$(ProjectDir)/../generated_demarshallers.cpp;$(ProjectDir)/../generated_marshallers.cpp"
> />
> </FileConfiguration>
> @@ -736,7 +744,7 @@
> <Tool
> Name="VCCustomBuildTool"
> Description="Generating old demarshaller"
> - CommandLine="generate1.bat"
> + CommandLine="generate1.bat
"
> AdditionalDependencies=""
> Outputs="$(ProjectDir)/../generated_demarshallers1.cpp;$(ProjectDir)/../generated_marshallers1.cpp"
> />
> @@ -747,7 +755,7 @@
> <Tool
> Name="VCCustomBuildTool"
> Description="Generating old demarshaller"
> - CommandLine="generate1.bat"
> + CommandLine="generate1.bat
"
> Outputs="$(ProjectDir)/../generated_demarshallers1.cpp;$(ProjectDir)/../generated_marshallers1.cpp"
> />
> </FileConfiguration>
> diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am
> index 02aa8eb..f6e9fda 100644
> --- a/client/x11/Makefile.am
> +++ b/client/x11/Makefile.am
> @@ -61,6 +61,8 @@ RED_COMMON_SRCS = \
> $(CLIENT_DIR)/debug.h \
> $(CLIENT_DIR)/display_channel.cpp \
> $(CLIENT_DIR)/display_channel.h \
> + $(CLIENT_DIR)/foreign_menu.cpp \
> + $(CLIENT_DIR)/foreign_menu.h \
> $(CLIENT_DIR)/glz_decoded_image.h \
> $(CLIENT_DIR)/glz_decoder_config.h \
> $(CLIENT_DIR)/glz_decoder.cpp \
More information about the Spice-devel
mailing list