mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-05 04:02:43 +00:00
spicec: add foreign menu
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.
This commit is contained in:
parent
e789c8b9aa
commit
20c550d278
@ -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 \
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
364
client/foreign_menu.cpp
Normal file
364
client/foreign_menu.cpp
Normal file
@ -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;
|
||||
}
|
||||
98
client/foreign_menu.h
Normal file
98
client/foreign_menu.h
Normal file
@ -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
|
||||
@ -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"
|
||||
@ -227,6 +227,10 @@
|
||||
RelativePath=".\event_sources_p.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\foreign_menu.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\gdi_canvas.cpp"
|
||||
>
|
||||
@ -507,6 +511,10 @@
|
||||
RelativePath=".\event_sources_p.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\foreign_menu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\common\gdi_canvas.h"
|
||||
>
|
||||
@ -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>
|
||||
|
||||
@ -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 \
|
||||
|
||||
Loading…
Reference in New Issue
Block a user